diff options
198 files changed, 4692 insertions, 15819 deletions
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt index 320f9336c781..89a339c9b079 100644 --- a/Documentation/nfc/nfc-hci.txt +++ b/Documentation/nfc/nfc-hci.txt | |||
@@ -178,3 +178,36 @@ ANY_GET_PARAMETER to the reader A gate to get information on the target | |||
178 | that was discovered). | 178 | that was discovered). |
179 | 179 | ||
180 | Typically, such an event will be propagated to NFC Core from MSGRXWQ context. | 180 | Typically, such an event will be propagated to NFC Core from MSGRXWQ context. |
181 | |||
182 | Error management | ||
183 | ---------------- | ||
184 | |||
185 | Errors that occur synchronously with the execution of an NFC Core request are | ||
186 | simply returned as the execution result of the request. These are easy. | ||
187 | |||
188 | Errors that occur asynchronously (e.g. in a background protocol handling thread) | ||
189 | must be reported such that upper layers don't stay ignorant that something | ||
190 | went wrong below and know that expected events will probably never happen. | ||
191 | Handling of these errors is done as follows: | ||
192 | |||
193 | - driver (pn544) fails to deliver an incoming frame: it stores the error such | ||
194 | that any subsequent call to the driver will result in this error. Then it calls | ||
195 | the standard nfc_shdlc_recv_frame() with a NULL argument to report the problem | ||
196 | above. shdlc stores a EREMOTEIO sticky status, which will trigger SMW to | ||
197 | report above in turn. | ||
198 | |||
199 | - SMW is basically a background thread to handle incoming and outgoing shdlc | ||
200 | frames. This thread will also check the shdlc sticky status and report to HCI | ||
201 | when it discovers it is not able to run anymore because of an unrecoverable | ||
202 | error that happened within shdlc or below. If the problem occurs during shdlc | ||
203 | connection, the error is reported through the connect completion. | ||
204 | |||
205 | - HCI: if an internal HCI error happens (frame is lost), or HCI is reported an | ||
206 | error from a lower layer, HCI will either complete the currently executing | ||
207 | command with that error, or notify NFC Core directly if no command is executing. | ||
208 | |||
209 | - NFC Core: when NFC Core is notified of an error from below and polling is | ||
210 | active, it will send a tag discovered event with an empty tag list to the user | ||
211 | space to let it know that the poll operation will never be able to detect a tag. | ||
212 | If polling is not active and the error was sticky, lower levels will return it | ||
213 | at next invocation. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index ce7398e1e1ec..b4321fb74698 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -3661,14 +3661,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git | |||
3661 | S: Supported | 3661 | S: Supported |
3662 | F: drivers/net/wireless/iwlwifi/ | 3662 | F: drivers/net/wireless/iwlwifi/ |
3663 | 3663 | ||
3664 | INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi) | ||
3665 | M: Samuel Ortiz <samuel.ortiz@intel.com> | ||
3666 | M: Intel Linux Wireless <ilw@linux.intel.com> | ||
3667 | L: linux-wireless@vger.kernel.org | ||
3668 | S: Supported | ||
3669 | W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi | ||
3670 | F: drivers/net/wireless/iwmc3200wifi/ | ||
3671 | |||
3672 | INTEL MANAGEMENT ENGINE (mei) | 3664 | INTEL MANAGEMENT ENGINE (mei) |
3673 | M: Tomas Winkler <tomas.winkler@intel.com> | 3665 | M: Tomas Winkler <tomas.winkler@intel.com> |
3674 | L: linux-kernel@vger.kernel.org | 3666 | L: linux-kernel@vger.kernel.org |
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index b81755bb4798..f6589eb7c45f 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h | |||
@@ -10,6 +10,15 @@ | |||
10 | 10 | ||
11 | #define BCMA_CORE_SIZE 0x1000 | 11 | #define BCMA_CORE_SIZE 0x1000 |
12 | 12 | ||
13 | #define bcma_err(bus, fmt, ...) \ | ||
14 | pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) | ||
15 | #define bcma_warn(bus, fmt, ...) \ | ||
16 | pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) | ||
17 | #define bcma_info(bus, fmt, ...) \ | ||
18 | pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) | ||
19 | #define bcma_debug(bus, fmt, ...) \ | ||
20 | pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) | ||
21 | |||
13 | struct bcma_bus; | 22 | struct bcma_bus; |
14 | 23 | ||
15 | /* main.c */ | 24 | /* main.c */ |
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index bc6e89212ad3..63c8b470536f 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c | |||
@@ -75,7 +75,7 @@ void bcma_core_set_clockmode(struct bcma_device *core, | |||
75 | udelay(10); | 75 | udelay(10); |
76 | } | 76 | } |
77 | if (i) | 77 | if (i) |
78 | pr_err("HT force timeout\n"); | 78 | bcma_err(core->bus, "HT force timeout\n"); |
79 | break; | 79 | break; |
80 | case BCMA_CLKMODE_DYNAMIC: | 80 | case BCMA_CLKMODE_DYNAMIC: |
81 | bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); | 81 | bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); |
@@ -102,9 +102,9 @@ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on) | |||
102 | udelay(10); | 102 | udelay(10); |
103 | } | 103 | } |
104 | if (i) | 104 | if (i) |
105 | pr_err("PLL enable timeout\n"); | 105 | bcma_err(core->bus, "PLL enable timeout\n"); |
106 | } else { | 106 | } else { |
107 | pr_warn("Disabling PLL not supported yet!\n"); | 107 | bcma_warn(core->bus, "Disabling PLL not supported yet!\n"); |
108 | } | 108 | } |
109 | } | 109 | } |
110 | EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); | 110 | EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); |
@@ -120,8 +120,8 @@ u32 bcma_core_dma_translation(struct bcma_device *core) | |||
120 | else | 120 | else |
121 | return BCMA_DMA_TRANSLATION_DMA32_CMT; | 121 | return BCMA_DMA_TRANSLATION_DMA32_CMT; |
122 | default: | 122 | default: |
123 | pr_err("DMA translation unknown for host %d\n", | 123 | bcma_err(core->bus, "DMA translation unknown for host %d\n", |
124 | core->bus->hosttype); | 124 | core->bus->hosttype); |
125 | } | 125 | } |
126 | return BCMA_DMA_TRANSLATION_NONE; | 126 | return BCMA_DMA_TRANSLATION_NONE; |
127 | } | 127 | } |
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index e9f1b3fd252c..a4c3ebcc4c86 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c | |||
@@ -44,7 +44,7 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) | |||
44 | if (cc->capabilities & BCMA_CC_CAP_PMU) | 44 | if (cc->capabilities & BCMA_CC_CAP_PMU) |
45 | bcma_pmu_init(cc); | 45 | bcma_pmu_init(cc); |
46 | if (cc->capabilities & BCMA_CC_CAP_PCTL) | 46 | if (cc->capabilities & BCMA_CC_CAP_PCTL) |
47 | pr_err("Power control not implemented!\n"); | 47 | bcma_err(cc->core->bus, "Power control not implemented!\n"); |
48 | 48 | ||
49 | if (cc->core->id.rev >= 16) { | 49 | if (cc->core->id.rev >= 16) { |
50 | if (cc->core->bus->sprom.leddc_on_time && | 50 | if (cc->core->bus->sprom.leddc_on_time && |
@@ -137,8 +137,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | |||
137 | | BCMA_CC_CORECTL_UARTCLKEN); | 137 | | BCMA_CC_CORECTL_UARTCLKEN); |
138 | } | 138 | } |
139 | } else { | 139 | } else { |
140 | pr_err("serial not supported on this device ccrev: 0x%x\n", | 140 | bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev); |
141 | ccrev); | ||
142 | return; | 141 | return; |
143 | } | 142 | } |
144 | 143 | ||
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 61ce4054b3c3..44326178db29 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c | |||
@@ -3,7 +3,8 @@ | |||
3 | * ChipCommon Power Management Unit driver | 3 | * ChipCommon Power Management Unit driver |
4 | * | 4 | * |
5 | * Copyright 2009, Michael Buesch <m@bues.ch> | 5 | * Copyright 2009, Michael Buesch <m@bues.ch> |
6 | * Copyright 2007, Broadcom Corporation | 6 | * Copyright 2007, 2011, Broadcom Corporation |
7 | * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de> | ||
7 | * | 8 | * |
8 | * Licensed under the GNU/GPL. See COPYING for details. | 9 | * Licensed under the GNU/GPL. See COPYING for details. |
9 | */ | 10 | */ |
@@ -54,39 +55,19 @@ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, | |||
54 | } | 55 | } |
55 | EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); | 56 | EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); |
56 | 57 | ||
57 | static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) | ||
58 | { | ||
59 | struct bcma_bus *bus = cc->core->bus; | ||
60 | |||
61 | switch (bus->chipinfo.id) { | ||
62 | case 0x4313: | ||
63 | case 0x4331: | ||
64 | case 43224: | ||
65 | case 43225: | ||
66 | break; | ||
67 | default: | ||
68 | pr_err("PLL init unknown for device 0x%04X\n", | ||
69 | bus->chipinfo.id); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) | 58 | static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) |
74 | { | 59 | { |
75 | struct bcma_bus *bus = cc->core->bus; | 60 | struct bcma_bus *bus = cc->core->bus; |
76 | u32 min_msk = 0, max_msk = 0; | 61 | u32 min_msk = 0, max_msk = 0; |
77 | 62 | ||
78 | switch (bus->chipinfo.id) { | 63 | switch (bus->chipinfo.id) { |
79 | case 0x4313: | 64 | case BCMA_CHIP_ID_BCM4313: |
80 | min_msk = 0x200D; | 65 | min_msk = 0x200D; |
81 | max_msk = 0xFFFF; | 66 | max_msk = 0xFFFF; |
82 | break; | 67 | break; |
83 | case 0x4331: | ||
84 | case 43224: | ||
85 | case 43225: | ||
86 | break; | ||
87 | default: | 68 | default: |
88 | pr_err("PMU resource config unknown for device 0x%04X\n", | 69 | bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n", |
89 | bus->chipinfo.id); | 70 | bus->chipinfo.id); |
90 | } | 71 | } |
91 | 72 | ||
92 | /* Set the resource masks. */ | 73 | /* Set the resource masks. */ |
@@ -94,22 +75,9 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) | |||
94 | bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); | 75 | bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); |
95 | if (max_msk) | 76 | if (max_msk) |
96 | bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); | 77 | bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); |
97 | } | ||
98 | |||
99 | void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) | ||
100 | { | ||
101 | struct bcma_bus *bus = cc->core->bus; | ||
102 | 78 | ||
103 | switch (bus->chipinfo.id) { | 79 | /* Add some delay; allow resources to come up and settle. */ |
104 | case 0x4313: | 80 | mdelay(2); |
105 | case 0x4331: | ||
106 | case 43224: | ||
107 | case 43225: | ||
108 | break; | ||
109 | default: | ||
110 | pr_err("PMU switch/regulators init unknown for device " | ||
111 | "0x%04X\n", bus->chipinfo.id); | ||
112 | } | ||
113 | } | 81 | } |
114 | 82 | ||
115 | /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ | 83 | /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ |
@@ -123,8 +91,11 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable) | |||
123 | val |= BCMA_CHIPCTL_4331_EXTPA_EN; | 91 | val |= BCMA_CHIPCTL_4331_EXTPA_EN; |
124 | if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) | 92 | if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) |
125 | val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | 93 | val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; |
94 | else if (bus->chipinfo.rev > 0) | ||
95 | val |= BCMA_CHIPCTL_4331_EXTPA_EN2; | ||
126 | } else { | 96 | } else { |
127 | val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; | 97 | val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; |
98 | val &= ~BCMA_CHIPCTL_4331_EXTPA_EN2; | ||
128 | val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | 99 | val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; |
129 | } | 100 | } |
130 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); | 101 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); |
@@ -135,28 +106,38 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) | |||
135 | struct bcma_bus *bus = cc->core->bus; | 106 | struct bcma_bus *bus = cc->core->bus; |
136 | 107 | ||
137 | switch (bus->chipinfo.id) { | 108 | switch (bus->chipinfo.id) { |
138 | case 0x4313: | 109 | case BCMA_CHIP_ID_BCM4313: |
139 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); | 110 | /* enable 12 mA drive strenth for 4313 and set chipControl |
111 | register bit 1 */ | ||
112 | bcma_chipco_chipctl_maskset(cc, 0, | ||
113 | BCMA_CCTRL_4313_12MA_LED_DRIVE, | ||
114 | BCMA_CCTRL_4313_12MA_LED_DRIVE); | ||
140 | break; | 115 | break; |
141 | case 0x4331: | 116 | case BCMA_CHIP_ID_BCM4331: |
142 | case 43431: | 117 | case BCMA_CHIP_ID_BCM43431: |
143 | /* Ext PA lines must be enabled for tx on BCM4331 */ | 118 | /* Ext PA lines must be enabled for tx on BCM4331 */ |
144 | bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true); | 119 | bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true); |
145 | break; | 120 | break; |
146 | case 43224: | 121 | case BCMA_CHIP_ID_BCM43224: |
122 | case BCMA_CHIP_ID_BCM43421: | ||
123 | /* enable 12 mA drive strenth for 43224 and set chipControl | ||
124 | register bit 15 */ | ||
147 | if (bus->chipinfo.rev == 0) { | 125 | if (bus->chipinfo.rev == 0) { |
148 | pr_err("Workarounds for 43224 rev 0 not fully " | 126 | bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL, |
149 | "implemented\n"); | 127 | BCMA_CCTRL_43224_GPIO_TOGGLE, |
150 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0); | 128 | BCMA_CCTRL_43224_GPIO_TOGGLE); |
129 | bcma_chipco_chipctl_maskset(cc, 0, | ||
130 | BCMA_CCTRL_43224A0_12MA_LED_DRIVE, | ||
131 | BCMA_CCTRL_43224A0_12MA_LED_DRIVE); | ||
151 | } else { | 132 | } else { |
152 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); | 133 | bcma_chipco_chipctl_maskset(cc, 0, |
134 | BCMA_CCTRL_43224B0_12MA_LED_DRIVE, | ||
135 | BCMA_CCTRL_43224B0_12MA_LED_DRIVE); | ||
153 | } | 136 | } |
154 | break; | 137 | break; |
155 | case 43225: | ||
156 | break; | ||
157 | default: | 138 | default: |
158 | pr_err("Workarounds unknown for device 0x%04X\n", | 139 | bcma_debug(bus, "Workarounds unknown or not needed for device 0x%04X\n", |
159 | bus->chipinfo.id); | 140 | bus->chipinfo.id); |
160 | } | 141 | } |
161 | } | 142 | } |
162 | 143 | ||
@@ -167,8 +148,8 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) | |||
167 | pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); | 148 | pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); |
168 | cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); | 149 | cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); |
169 | 150 | ||
170 | pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev, | 151 | bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n", |
171 | pmucap); | 152 | cc->pmu.rev, pmucap); |
172 | 153 | ||
173 | if (cc->pmu.rev == 1) | 154 | if (cc->pmu.rev == 1) |
174 | bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, | 155 | bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, |
@@ -177,12 +158,7 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) | |||
177 | bcma_cc_set32(cc, BCMA_CC_PMU_CTL, | 158 | bcma_cc_set32(cc, BCMA_CC_PMU_CTL, |
178 | BCMA_CC_PMU_CTL_NOILPONW); | 159 | BCMA_CC_PMU_CTL_NOILPONW); |
179 | 160 | ||
180 | if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2) | ||
181 | pr_err("Fix for 4329b0 bad LPOM state not implemented!\n"); | ||
182 | |||
183 | bcma_pmu_pll_init(cc); | ||
184 | bcma_pmu_resources_init(cc); | 161 | bcma_pmu_resources_init(cc); |
185 | bcma_pmu_swreg_init(cc); | ||
186 | bcma_pmu_workarounds(cc); | 162 | bcma_pmu_workarounds(cc); |
187 | } | 163 | } |
188 | 164 | ||
@@ -191,23 +167,22 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) | |||
191 | struct bcma_bus *bus = cc->core->bus; | 167 | struct bcma_bus *bus = cc->core->bus; |
192 | 168 | ||
193 | switch (bus->chipinfo.id) { | 169 | switch (bus->chipinfo.id) { |
194 | case 0x4716: | 170 | case BCMA_CHIP_ID_BCM4716: |
195 | case 0x4748: | 171 | case BCMA_CHIP_ID_BCM4748: |
196 | case 47162: | 172 | case BCMA_CHIP_ID_BCM47162: |
197 | case 0x4313: | 173 | case BCMA_CHIP_ID_BCM4313: |
198 | case 0x5357: | 174 | case BCMA_CHIP_ID_BCM5357: |
199 | case 0x4749: | 175 | case BCMA_CHIP_ID_BCM4749: |
200 | case 53572: | 176 | case BCMA_CHIP_ID_BCM53572: |
201 | /* always 20Mhz */ | 177 | /* always 20Mhz */ |
202 | return 20000 * 1000; | 178 | return 20000 * 1000; |
203 | case 0x5356: | 179 | case BCMA_CHIP_ID_BCM5356: |
204 | case 0x5300: | 180 | case BCMA_CHIP_ID_BCM4706: |
205 | /* always 25Mhz */ | 181 | /* always 25Mhz */ |
206 | return 25000 * 1000; | 182 | return 25000 * 1000; |
207 | default: | 183 | default: |
208 | pr_warn("No ALP clock specified for %04X device, " | 184 | bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n", |
209 | "pmu rev. %d, using default %d Hz\n", | 185 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); |
210 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); | ||
211 | } | 186 | } |
212 | return BCMA_CC_PMU_ALP_CLOCK; | 187 | return BCMA_CC_PMU_ALP_CLOCK; |
213 | } | 188 | } |
@@ -224,7 +199,8 @@ static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | |||
224 | 199 | ||
225 | BUG_ON(!m || m > 4); | 200 | BUG_ON(!m || m > 4); |
226 | 201 | ||
227 | if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { | 202 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || |
203 | bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) { | ||
228 | /* Detect failure in clock setting */ | 204 | /* Detect failure in clock setting */ |
229 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | 205 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); |
230 | if (tmp & 0x40000) | 206 | if (tmp & 0x40000) |
@@ -250,33 +226,62 @@ static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | |||
250 | return (fc / div) * 1000000; | 226 | return (fc / div) * 1000000; |
251 | } | 227 | } |
252 | 228 | ||
229 | static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m) | ||
230 | { | ||
231 | u32 tmp, ndiv, p1div, p2div; | ||
232 | u32 clock; | ||
233 | |||
234 | BUG_ON(!m || m > 4); | ||
235 | |||
236 | /* Get N, P1 and P2 dividers to determine CPU clock */ | ||
237 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PMU6_4706_PROCPLL_OFF); | ||
238 | ndiv = (tmp & BCMA_CC_PMU6_4706_PROC_NDIV_INT_MASK) | ||
239 | >> BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT; | ||
240 | p1div = (tmp & BCMA_CC_PMU6_4706_PROC_P1DIV_MASK) | ||
241 | >> BCMA_CC_PMU6_4706_PROC_P1DIV_SHIFT; | ||
242 | p2div = (tmp & BCMA_CC_PMU6_4706_PROC_P2DIV_MASK) | ||
243 | >> BCMA_CC_PMU6_4706_PROC_P2DIV_SHIFT; | ||
244 | |||
245 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | ||
246 | if (tmp & BCMA_CC_CHIPST_4706_PKG_OPTION) | ||
247 | /* Low cost bonding: Fixed reference clock 25MHz and m = 4 */ | ||
248 | clock = (25000000 / 4) * ndiv * p2div / p1div; | ||
249 | else | ||
250 | /* Fixed reference clock 25MHz and m = 2 */ | ||
251 | clock = (25000000 / 2) * ndiv * p2div / p1div; | ||
252 | |||
253 | if (m == BCMA_CC_PMU5_MAINPLL_SSB) | ||
254 | clock = clock / 4; | ||
255 | |||
256 | return clock; | ||
257 | } | ||
258 | |||
253 | /* query bus clock frequency for PMU-enabled chipcommon */ | 259 | /* query bus clock frequency for PMU-enabled chipcommon */ |
254 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) | 260 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) |
255 | { | 261 | { |
256 | struct bcma_bus *bus = cc->core->bus; | 262 | struct bcma_bus *bus = cc->core->bus; |
257 | 263 | ||
258 | switch (bus->chipinfo.id) { | 264 | switch (bus->chipinfo.id) { |
259 | case 0x4716: | 265 | case BCMA_CHIP_ID_BCM4716: |
260 | case 0x4748: | 266 | case BCMA_CHIP_ID_BCM4748: |
261 | case 47162: | 267 | case BCMA_CHIP_ID_BCM47162: |
262 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, | 268 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, |
263 | BCMA_CC_PMU5_MAINPLL_SSB); | 269 | BCMA_CC_PMU5_MAINPLL_SSB); |
264 | case 0x5356: | 270 | case BCMA_CHIP_ID_BCM5356: |
265 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, | 271 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, |
266 | BCMA_CC_PMU5_MAINPLL_SSB); | 272 | BCMA_CC_PMU5_MAINPLL_SSB); |
267 | case 0x5357: | 273 | case BCMA_CHIP_ID_BCM5357: |
268 | case 0x4749: | 274 | case BCMA_CHIP_ID_BCM4749: |
269 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, | 275 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, |
270 | BCMA_CC_PMU5_MAINPLL_SSB); | 276 | BCMA_CC_PMU5_MAINPLL_SSB); |
271 | case 0x5300: | 277 | case BCMA_CHIP_ID_BCM4706: |
272 | return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, | 278 | return bcma_pmu_clock_bcm4706(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, |
273 | BCMA_CC_PMU5_MAINPLL_SSB); | 279 | BCMA_CC_PMU5_MAINPLL_SSB); |
274 | case 53572: | 280 | case BCMA_CHIP_ID_BCM53572: |
275 | return 75000000; | 281 | return 75000000; |
276 | default: | 282 | default: |
277 | pr_warn("No backplane clock specified for %04X device, " | 283 | bcma_warn(bus, "No backplane clock specified for %04X device, pmu rev. %d, using default %d Hz\n", |
278 | "pmu rev. %d, using default %d Hz\n", | 284 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); |
279 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); | ||
280 | } | 285 | } |
281 | return BCMA_CC_PMU_HT_CLOCK; | 286 | return BCMA_CC_PMU_HT_CLOCK; |
282 | } | 287 | } |
@@ -286,17 +291,21 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | |||
286 | { | 291 | { |
287 | struct bcma_bus *bus = cc->core->bus; | 292 | struct bcma_bus *bus = cc->core->bus; |
288 | 293 | ||
289 | if (bus->chipinfo.id == 53572) | 294 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) |
290 | return 300000000; | 295 | return 300000000; |
291 | 296 | ||
292 | if (cc->pmu.rev >= 5) { | 297 | if (cc->pmu.rev >= 5) { |
293 | u32 pll; | 298 | u32 pll; |
294 | switch (bus->chipinfo.id) { | 299 | switch (bus->chipinfo.id) { |
295 | case 0x5356: | 300 | case BCMA_CHIP_ID_BCM4706: |
301 | return bcma_pmu_clock_bcm4706(cc, | ||
302 | BCMA_CC_PMU4706_MAINPLL_PLL0, | ||
303 | BCMA_CC_PMU5_MAINPLL_CPU); | ||
304 | case BCMA_CHIP_ID_BCM5356: | ||
296 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; | 305 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; |
297 | break; | 306 | break; |
298 | case 0x5357: | 307 | case BCMA_CHIP_ID_BCM5357: |
299 | case 0x4749: | 308 | case BCMA_CHIP_ID_BCM4749: |
300 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; | 309 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; |
301 | break; | 310 | break; |
302 | default: | 311 | default: |
@@ -304,10 +313,188 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | |||
304 | break; | 313 | break; |
305 | } | 314 | } |
306 | 315 | ||
307 | /* TODO: if (bus->chipinfo.id == 0x5300) | ||
308 | return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ | ||
309 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); | 316 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); |
310 | } | 317 | } |
311 | 318 | ||
312 | return bcma_pmu_get_clockcontrol(cc); | 319 | return bcma_pmu_get_clockcontrol(cc); |
313 | } | 320 | } |
321 | |||
322 | static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset, | ||
323 | u32 value) | ||
324 | { | ||
325 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
326 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value); | ||
327 | } | ||
328 | |||
329 | void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) | ||
330 | { | ||
331 | u32 tmp = 0; | ||
332 | u8 phypll_offset = 0; | ||
333 | u8 bcm5357_bcm43236_p1div[] = {0x1, 0x5, 0x5}; | ||
334 | u8 bcm5357_bcm43236_ndiv[] = {0x30, 0xf6, 0xfc}; | ||
335 | struct bcma_bus *bus = cc->core->bus; | ||
336 | |||
337 | switch (bus->chipinfo.id) { | ||
338 | case BCMA_CHIP_ID_BCM5357: | ||
339 | case BCMA_CHIP_ID_BCM4749: | ||
340 | case BCMA_CHIP_ID_BCM53572: | ||
341 | /* 5357[ab]0, 43236[ab]0, and 6362b0 */ | ||
342 | |||
343 | /* BCM5357 needs to touch PLL1_PLLCTL[02], | ||
344 | so offset PLL0_PLLCTL[02] by 6 */ | ||
345 | phypll_offset = (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || | ||
346 | bus->chipinfo.id == BCMA_CHIP_ID_BCM4749 || | ||
347 | bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0; | ||
348 | |||
349 | /* RMW only the P1 divider */ | ||
350 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, | ||
351 | BCMA_CC_PMU_PLL_CTL0 + phypll_offset); | ||
352 | tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
353 | tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK)); | ||
354 | tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT); | ||
355 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp); | ||
356 | |||
357 | /* RMW only the int feedback divider */ | ||
358 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, | ||
359 | BCMA_CC_PMU_PLL_CTL2 + phypll_offset); | ||
360 | tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
361 | tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK); | ||
362 | tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT; | ||
363 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp); | ||
364 | |||
365 | tmp = 1 << 10; | ||
366 | break; | ||
367 | |||
368 | case BCMA_CHIP_ID_BCM4331: | ||
369 | case BCMA_CHIP_ID_BCM43431: | ||
370 | if (spuravoid == 2) { | ||
371 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
372 | 0x11500014); | ||
373 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
374 | 0x0FC00a08); | ||
375 | } else if (spuravoid == 1) { | ||
376 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
377 | 0x11500014); | ||
378 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
379 | 0x0F600a08); | ||
380 | } else { | ||
381 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
382 | 0x11100014); | ||
383 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
384 | 0x03000a08); | ||
385 | } | ||
386 | tmp = 1 << 10; | ||
387 | break; | ||
388 | |||
389 | case BCMA_CHIP_ID_BCM43224: | ||
390 | case BCMA_CHIP_ID_BCM43225: | ||
391 | case BCMA_CHIP_ID_BCM43421: | ||
392 | if (spuravoid == 1) { | ||
393 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
394 | 0x11500010); | ||
395 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
396 | 0x000C0C06); | ||
397 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
398 | 0x0F600a08); | ||
399 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
400 | 0x00000000); | ||
401 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
402 | 0x2001E920); | ||
403 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
404 | 0x88888815); | ||
405 | } else { | ||
406 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
407 | 0x11100010); | ||
408 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
409 | 0x000c0c06); | ||
410 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
411 | 0x03000a08); | ||
412 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
413 | 0x00000000); | ||
414 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
415 | 0x200005c0); | ||
416 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
417 | 0x88888815); | ||
418 | } | ||
419 | tmp = 1 << 10; | ||
420 | break; | ||
421 | |||
422 | case BCMA_CHIP_ID_BCM4716: | ||
423 | case BCMA_CHIP_ID_BCM4748: | ||
424 | case BCMA_CHIP_ID_BCM47162: | ||
425 | if (spuravoid == 1) { | ||
426 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
427 | 0x11500060); | ||
428 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
429 | 0x080C0C06); | ||
430 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
431 | 0x0F600000); | ||
432 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
433 | 0x00000000); | ||
434 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
435 | 0x2001E924); | ||
436 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
437 | 0x88888815); | ||
438 | } else { | ||
439 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
440 | 0x11100060); | ||
441 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
442 | 0x080c0c06); | ||
443 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
444 | 0x03000000); | ||
445 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
446 | 0x00000000); | ||
447 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
448 | 0x200005c0); | ||
449 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
450 | 0x88888815); | ||
451 | } | ||
452 | |||
453 | tmp = 3 << 9; | ||
454 | break; | ||
455 | |||
456 | case BCMA_CHIP_ID_BCM43227: | ||
457 | case BCMA_CHIP_ID_BCM43228: | ||
458 | case BCMA_CHIP_ID_BCM43428: | ||
459 | /* LCNXN */ | ||
460 | /* PLL Settings for spur avoidance on/off mode, | ||
461 | no on2 support for 43228A0 */ | ||
462 | if (spuravoid == 1) { | ||
463 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
464 | 0x01100014); | ||
465 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
466 | 0x040C0C06); | ||
467 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
468 | 0x03140A08); | ||
469 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
470 | 0x00333333); | ||
471 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
472 | 0x202C2820); | ||
473 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
474 | 0x88888815); | ||
475 | } else { | ||
476 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, | ||
477 | 0x11100014); | ||
478 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, | ||
479 | 0x040c0c06); | ||
480 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, | ||
481 | 0x03000a08); | ||
482 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, | ||
483 | 0x00000000); | ||
484 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, | ||
485 | 0x200005c0); | ||
486 | bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, | ||
487 | 0x88888815); | ||
488 | } | ||
489 | tmp = 1 << 10; | ||
490 | break; | ||
491 | default: | ||
492 | bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n", | ||
493 | bus->chipinfo.id); | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL); | ||
498 | bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp); | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate); | ||
diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index c3e9dff4224e..ef34ed25bf00 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c | |||
@@ -22,15 +22,15 @@ | |||
22 | /* The 47162a0 hangs when reading MIPS DMP registers registers */ | 22 | /* The 47162a0 hangs when reading MIPS DMP registers registers */ |
23 | static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) | 23 | static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) |
24 | { | 24 | { |
25 | return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 && | 25 | return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 && |
26 | dev->id.id == BCMA_CORE_MIPS_74K; | 26 | dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K; |
27 | } | 27 | } |
28 | 28 | ||
29 | /* The 5357b0 hangs when reading USB20H DMP registers */ | 29 | /* The 5357b0 hangs when reading USB20H DMP registers */ |
30 | static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) | 30 | static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) |
31 | { | 31 | { |
32 | return (dev->bus->chipinfo.id == 0x5357 || | 32 | return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || |
33 | dev->bus->chipinfo.id == 0x4749) && | 33 | dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) && |
34 | dev->bus->chipinfo.pkg == 11 && | 34 | dev->bus->chipinfo.pkg == 11 && |
35 | dev->id.id == BCMA_CORE_USB20_HOST; | 35 | dev->id.id == BCMA_CORE_USB20_HOST; |
36 | } | 36 | } |
@@ -143,8 +143,8 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) | |||
143 | 1 << irqflag); | 143 | 1 << irqflag); |
144 | } | 144 | } |
145 | 145 | ||
146 | pr_info("set_irq: core 0x%04x, irq %d => %d\n", | 146 | bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n", |
147 | dev->id.id, oldirq + 2, irq + 2); | 147 | dev->id.id, oldirq + 2, irq + 2); |
148 | } | 148 | } |
149 | 149 | ||
150 | static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) | 150 | static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) |
@@ -173,7 +173,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) | |||
173 | if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) | 173 | if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) |
174 | return bcma_pmu_get_clockcpu(&bus->drv_cc); | 174 | return bcma_pmu_get_clockcpu(&bus->drv_cc); |
175 | 175 | ||
176 | pr_err("No PMU available, need this to get the cpu clock\n"); | 176 | bcma_err(bus, "No PMU available, need this to get the cpu clock\n"); |
177 | return 0; | 177 | return 0; |
178 | } | 178 | } |
179 | EXPORT_SYMBOL(bcma_cpu_clock); | 179 | EXPORT_SYMBOL(bcma_cpu_clock); |
@@ -185,10 +185,10 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) | |||
185 | switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { | 185 | switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { |
186 | case BCMA_CC_FLASHT_STSER: | 186 | case BCMA_CC_FLASHT_STSER: |
187 | case BCMA_CC_FLASHT_ATSER: | 187 | case BCMA_CC_FLASHT_ATSER: |
188 | pr_err("Serial flash not supported.\n"); | 188 | bcma_err(bus, "Serial flash not supported.\n"); |
189 | break; | 189 | break; |
190 | case BCMA_CC_FLASHT_PARA: | 190 | case BCMA_CC_FLASHT_PARA: |
191 | pr_info("found parallel flash.\n"); | 191 | bcma_info(bus, "found parallel flash.\n"); |
192 | bus->drv_cc.pflash.window = 0x1c000000; | 192 | bus->drv_cc.pflash.window = 0x1c000000; |
193 | bus->drv_cc.pflash.window_size = 0x02000000; | 193 | bus->drv_cc.pflash.window_size = 0x02000000; |
194 | 194 | ||
@@ -199,7 +199,7 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) | |||
199 | bus->drv_cc.pflash.buswidth = 2; | 199 | bus->drv_cc.pflash.buswidth = 2; |
200 | break; | 200 | break; |
201 | default: | 201 | default: |
202 | pr_err("flash not supported.\n"); | 202 | bcma_err(bus, "flash not supported.\n"); |
203 | } | 203 | } |
204 | } | 204 | } |
205 | 205 | ||
@@ -209,7 +209,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) | |||
209 | struct bcma_device *core; | 209 | struct bcma_device *core; |
210 | bus = mcore->core->bus; | 210 | bus = mcore->core->bus; |
211 | 211 | ||
212 | pr_info("Initializing MIPS core...\n"); | 212 | bcma_info(bus, "Initializing MIPS core...\n"); |
213 | 213 | ||
214 | if (!mcore->setup_done) | 214 | if (!mcore->setup_done) |
215 | mcore->assigned_irqs = 1; | 215 | mcore->assigned_irqs = 1; |
@@ -244,7 +244,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) | |||
244 | break; | 244 | break; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | pr_info("IRQ reconfiguration done\n"); | 247 | bcma_info(bus, "IRQ reconfiguration done\n"); |
248 | bcma_core_mips_dump_irq(bus); | 248 | bcma_core_mips_dump_irq(bus); |
249 | 249 | ||
250 | if (mcore->setup_done) | 250 | if (mcore->setup_done) |
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index b9a86edfec39..cbae2c231336 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c | |||
@@ -36,7 +36,7 @@ bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) | |||
36 | return false; | 36 | return false; |
37 | 37 | ||
38 | if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) { | 38 | if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) { |
39 | pr_info("This PCI core is disabled and not working\n"); | 39 | bcma_info(bus, "This PCI core is disabled and not working\n"); |
40 | return false; | 40 | return false; |
41 | } | 41 | } |
42 | 42 | ||
@@ -215,7 +215,8 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, | |||
215 | } else { | 215 | } else { |
216 | writel(val, mmio); | 216 | writel(val, mmio); |
217 | 217 | ||
218 | if (chipid == 0x4716 || chipid == 0x4748) | 218 | if (chipid == BCMA_CHIP_ID_BCM4716 || |
219 | chipid == BCMA_CHIP_ID_BCM4748) | ||
219 | readl(mmio); | 220 | readl(mmio); |
220 | } | 221 | } |
221 | 222 | ||
@@ -340,6 +341,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc, | |||
340 | */ | 341 | */ |
341 | static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc) | 342 | static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc) |
342 | { | 343 | { |
344 | struct bcma_bus *bus = pc->core->bus; | ||
343 | u8 cap_ptr, root_ctrl, root_cap, dev; | 345 | u8 cap_ptr, root_ctrl, root_cap, dev; |
344 | u16 val16; | 346 | u16 val16; |
345 | int i; | 347 | int i; |
@@ -378,7 +380,8 @@ static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc) | |||
378 | udelay(10); | 380 | udelay(10); |
379 | } | 381 | } |
380 | if (val16 == 0x1) | 382 | if (val16 == 0x1) |
381 | pr_err("PCI: Broken device in slot %d\n", dev); | 383 | bcma_err(bus, "PCI: Broken device in slot %d\n", |
384 | dev); | ||
382 | } | 385 | } |
383 | } | 386 | } |
384 | } | 387 | } |
@@ -391,11 +394,11 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) | |||
391 | u32 pci_membase_1G; | 394 | u32 pci_membase_1G; |
392 | unsigned long io_map_base; | 395 | unsigned long io_map_base; |
393 | 396 | ||
394 | pr_info("PCIEcore in host mode found\n"); | 397 | bcma_info(bus, "PCIEcore in host mode found\n"); |
395 | 398 | ||
396 | pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL); | 399 | pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL); |
397 | if (!pc_host) { | 400 | if (!pc_host) { |
398 | pr_err("can not allocate memory"); | 401 | bcma_err(bus, "can not allocate memory"); |
399 | return; | 402 | return; |
400 | } | 403 | } |
401 | 404 | ||
@@ -434,13 +437,14 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) | |||
434 | * as mips can't generate 64-bit address on the | 437 | * as mips can't generate 64-bit address on the |
435 | * backplane. | 438 | * backplane. |
436 | */ | 439 | */ |
437 | if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) { | 440 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4716 || |
441 | bus->chipinfo.id == BCMA_CHIP_ID_BCM4748) { | ||
438 | pc_host->mem_resource.start = BCMA_SOC_PCI_MEM; | 442 | pc_host->mem_resource.start = BCMA_SOC_PCI_MEM; |
439 | pc_host->mem_resource.end = BCMA_SOC_PCI_MEM + | 443 | pc_host->mem_resource.end = BCMA_SOC_PCI_MEM + |
440 | BCMA_SOC_PCI_MEM_SZ - 1; | 444 | BCMA_SOC_PCI_MEM_SZ - 1; |
441 | pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0, | 445 | pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0, |
442 | BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM); | 446 | BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM); |
443 | } else if (bus->chipinfo.id == 0x5300) { | 447 | } else if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { |
444 | tmp = BCMA_CORE_PCI_SBTOPCI_MEM; | 448 | tmp = BCMA_CORE_PCI_SBTOPCI_MEM; |
445 | tmp |= BCMA_CORE_PCI_SBTOPCI_PREF; | 449 | tmp |= BCMA_CORE_PCI_SBTOPCI_PREF; |
446 | tmp |= BCMA_CORE_PCI_SBTOPCI_BURST; | 450 | tmp |= BCMA_CORE_PCI_SBTOPCI_BURST; |
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 6c05cf470f96..11b32d2642df 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c | |||
@@ -18,7 +18,7 @@ static void bcma_host_pci_switch_core(struct bcma_device *core) | |||
18 | pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, | 18 | pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, |
19 | core->wrap); | 19 | core->wrap); |
20 | core->bus->mapped_core = core; | 20 | core->bus->mapped_core = core; |
21 | pr_debug("Switched to core: 0x%X\n", core->id.id); | 21 | bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id); |
22 | } | 22 | } |
23 | 23 | ||
24 | /* Provides access to the requested core. Returns base offset that has to be | 24 | /* Provides access to the requested core. Returns base offset that has to be |
@@ -188,7 +188,7 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev, | |||
188 | 188 | ||
189 | /* SSB needed additional powering up, do we have any AMBA PCI cards? */ | 189 | /* SSB needed additional powering up, do we have any AMBA PCI cards? */ |
190 | if (!pci_is_pcie(dev)) | 190 | if (!pci_is_pcie(dev)) |
191 | pr_err("PCI card detected, report problems.\n"); | 191 | bcma_err(bus, "PCI card detected, report problems.\n"); |
192 | 192 | ||
193 | /* Map MMIO */ | 193 | /* Map MMIO */ |
194 | err = -ENOMEM; | 194 | err = -ENOMEM; |
@@ -268,6 +268,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend, | |||
268 | 268 | ||
269 | static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { | 269 | static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { |
270 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, | 270 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, |
271 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, | ||
271 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, | 272 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, |
272 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, | 273 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, |
273 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, | 274 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, |
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7e138ec21357..7ff4bac6f9e1 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c | |||
@@ -118,8 +118,9 @@ static int bcma_register_cores(struct bcma_bus *bus) | |||
118 | 118 | ||
119 | err = device_register(&core->dev); | 119 | err = device_register(&core->dev); |
120 | if (err) { | 120 | if (err) { |
121 | pr_err("Could not register dev for core 0x%03X\n", | 121 | bcma_err(bus, |
122 | core->id.id); | 122 | "Could not register dev for core 0x%03X\n", |
123 | core->id.id); | ||
123 | continue; | 124 | continue; |
124 | } | 125 | } |
125 | core->dev_registered = true; | 126 | core->dev_registered = true; |
@@ -151,7 +152,7 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) | |||
151 | /* Scan for devices (cores) */ | 152 | /* Scan for devices (cores) */ |
152 | err = bcma_bus_scan(bus); | 153 | err = bcma_bus_scan(bus); |
153 | if (err) { | 154 | if (err) { |
154 | pr_err("Failed to scan: %d\n", err); | 155 | bcma_err(bus, "Failed to scan: %d\n", err); |
155 | return -1; | 156 | return -1; |
156 | } | 157 | } |
157 | 158 | ||
@@ -179,14 +180,14 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) | |||
179 | /* Try to get SPROM */ | 180 | /* Try to get SPROM */ |
180 | err = bcma_sprom_get(bus); | 181 | err = bcma_sprom_get(bus); |
181 | if (err == -ENOENT) { | 182 | if (err == -ENOENT) { |
182 | pr_err("No SPROM available\n"); | 183 | bcma_err(bus, "No SPROM available\n"); |
183 | } else if (err) | 184 | } else if (err) |
184 | pr_err("Failed to get SPROM: %d\n", err); | 185 | bcma_err(bus, "Failed to get SPROM: %d\n", err); |
185 | 186 | ||
186 | /* Register found cores */ | 187 | /* Register found cores */ |
187 | bcma_register_cores(bus); | 188 | bcma_register_cores(bus); |
188 | 189 | ||
189 | pr_info("Bus registered\n"); | 190 | bcma_info(bus, "Bus registered\n"); |
190 | 191 | ||
191 | return 0; | 192 | return 0; |
192 | } | 193 | } |
@@ -214,7 +215,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, | |||
214 | /* Scan for chip common core */ | 215 | /* Scan for chip common core */ |
215 | err = bcma_bus_scan_early(bus, &match, core_cc); | 216 | err = bcma_bus_scan_early(bus, &match, core_cc); |
216 | if (err) { | 217 | if (err) { |
217 | pr_err("Failed to scan for common core: %d\n", err); | 218 | bcma_err(bus, "Failed to scan for common core: %d\n", err); |
218 | return -1; | 219 | return -1; |
219 | } | 220 | } |
220 | 221 | ||
@@ -226,7 +227,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, | |||
226 | /* Scan for mips core */ | 227 | /* Scan for mips core */ |
227 | err = bcma_bus_scan_early(bus, &match, core_mips); | 228 | err = bcma_bus_scan_early(bus, &match, core_mips); |
228 | if (err) { | 229 | if (err) { |
229 | pr_err("Failed to scan for mips core: %d\n", err); | 230 | bcma_err(bus, "Failed to scan for mips core: %d\n", err); |
230 | return -1; | 231 | return -1; |
231 | } | 232 | } |
232 | 233 | ||
@@ -244,7 +245,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, | |||
244 | bcma_core_mips_init(&bus->drv_mips); | 245 | bcma_core_mips_init(&bus->drv_mips); |
245 | } | 246 | } |
246 | 247 | ||
247 | pr_info("Early bus registered\n"); | 248 | bcma_info(bus, "Early bus registered\n"); |
248 | 249 | ||
249 | return 0; | 250 | return 0; |
250 | } | 251 | } |
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index a3420585d942..a0272bbfc4f6 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c | |||
@@ -340,7 +340,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, | |||
340 | if (tmp <= 0) { | 340 | if (tmp <= 0) { |
341 | return -EILSEQ; | 341 | return -EILSEQ; |
342 | } else { | 342 | } else { |
343 | pr_info("Bridge found\n"); | 343 | bcma_info(bus, "Bridge found\n"); |
344 | return -ENXIO; | 344 | return -ENXIO; |
345 | } | 345 | } |
346 | } | 346 | } |
@@ -427,8 +427,8 @@ void bcma_init_bus(struct bcma_bus *bus) | |||
427 | chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; | 427 | chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; |
428 | chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; | 428 | chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; |
429 | chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; | 429 | chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; |
430 | pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", | 430 | bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", |
431 | chipinfo->id, chipinfo->rev, chipinfo->pkg); | 431 | chipinfo->id, chipinfo->rev, chipinfo->pkg); |
432 | 432 | ||
433 | bus->init_done = true; | 433 | bus->init_done = true; |
434 | } | 434 | } |
@@ -482,11 +482,10 @@ int bcma_bus_scan(struct bcma_bus *bus) | |||
482 | other_core = bcma_find_core_reverse(bus, core->id.id); | 482 | other_core = bcma_find_core_reverse(bus, core->id.id); |
483 | core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1; | 483 | core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1; |
484 | 484 | ||
485 | pr_info("Core %d found: %s " | 485 | bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
486 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 486 | core->core_index, bcma_device_name(&core->id), |
487 | core->core_index, bcma_device_name(&core->id), | 487 | core->id.manuf, core->id.id, core->id.rev, |
488 | core->id.manuf, core->id.id, core->id.rev, | 488 | core->id.class); |
489 | core->id.class); | ||
490 | 489 | ||
491 | list_add(&core->list, &bus->cores); | 490 | list_add(&core->list, &bus->cores); |
492 | } | 491 | } |
@@ -538,11 +537,10 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus, | |||
538 | 537 | ||
539 | core->core_index = core_num++; | 538 | core->core_index = core_num++; |
540 | bus->nr_cores++; | 539 | bus->nr_cores++; |
541 | pr_info("Core %d found: %s " | 540 | bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", |
542 | "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", | 541 | core->core_index, bcma_device_name(&core->id), |
543 | core->core_index, bcma_device_name(&core->id), | 542 | core->id.manuf, core->id.id, core->id.rev, |
544 | core->id.manuf, core->id.id, core->id.rev, | 543 | core->id.class); |
545 | core->id.class); | ||
546 | 544 | ||
547 | list_add(&core->list, &bus->cores); | 545 | list_add(&core->list, &bus->cores); |
548 | err = 0; | 546 | err = 0; |
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index f16f42d36071..26823d97fd9f 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
@@ -60,11 +60,11 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, | |||
60 | if (err) | 60 | if (err) |
61 | goto fail; | 61 | goto fail; |
62 | 62 | ||
63 | pr_debug("Using SPROM revision %d provided by" | 63 | bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", |
64 | " platform.\n", bus->sprom.revision); | 64 | bus->sprom.revision); |
65 | return 0; | 65 | return 0; |
66 | fail: | 66 | fail: |
67 | pr_warn("Using fallback SPROM failed (err %d)\n", err); | 67 | bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); |
68 | return err; | 68 | return err; |
69 | } | 69 | } |
70 | 70 | ||
@@ -468,11 +468,11 @@ static bool bcma_sprom_ext_available(struct bcma_bus *bus) | |||
468 | /* older chipcommon revisions use chip status register */ | 468 | /* older chipcommon revisions use chip status register */ |
469 | chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); | 469 | chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); |
470 | switch (bus->chipinfo.id) { | 470 | switch (bus->chipinfo.id) { |
471 | case 0x4313: | 471 | case BCMA_CHIP_ID_BCM4313: |
472 | present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT; | 472 | present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT; |
473 | break; | 473 | break; |
474 | 474 | ||
475 | case 0x4331: | 475 | case BCMA_CHIP_ID_BCM4331: |
476 | present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT; | 476 | present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT; |
477 | break; | 477 | break; |
478 | 478 | ||
@@ -494,16 +494,16 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) | |||
494 | 494 | ||
495 | chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); | 495 | chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); |
496 | switch (bus->chipinfo.id) { | 496 | switch (bus->chipinfo.id) { |
497 | case 0x4313: | 497 | case BCMA_CHIP_ID_BCM4313: |
498 | present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT; | 498 | present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT; |
499 | break; | 499 | break; |
500 | 500 | ||
501 | case 0x4331: | 501 | case BCMA_CHIP_ID_BCM4331: |
502 | present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; | 502 | present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; |
503 | break; | 503 | break; |
504 | 504 | ||
505 | case 43224: | 505 | case BCMA_CHIP_ID_BCM43224: |
506 | case 43225: | 506 | case BCMA_CHIP_ID_BCM43225: |
507 | /* for these chips OTP is always available */ | 507 | /* for these chips OTP is always available */ |
508 | present = true; | 508 | present = true; |
509 | break; | 509 | break; |
@@ -579,13 +579,15 @@ int bcma_sprom_get(struct bcma_bus *bus) | |||
579 | if (!sprom) | 579 | if (!sprom) |
580 | return -ENOMEM; | 580 | return -ENOMEM; |
581 | 581 | ||
582 | if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) | 582 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || |
583 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) | ||
583 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); | 584 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); |
584 | 585 | ||
585 | pr_debug("SPROM offset 0x%x\n", offset); | 586 | bcma_debug(bus, "SPROM offset 0x%x\n", offset); |
586 | bcma_sprom_read(bus, offset, sprom); | 587 | bcma_sprom_read(bus, offset, sprom); |
587 | 588 | ||
588 | if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) | 589 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || |
590 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) | ||
589 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); | 591 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); |
590 | 592 | ||
591 | err = bcma_sprom_valid(sprom); | 593 | err = bcma_sprom_valid(sprom); |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2661f6e366f9..154f3ef07631 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -511,7 +511,6 @@ config USB_SWITCH_FSA9480 | |||
511 | source "drivers/misc/c2port/Kconfig" | 511 | source "drivers/misc/c2port/Kconfig" |
512 | source "drivers/misc/eeprom/Kconfig" | 512 | source "drivers/misc/eeprom/Kconfig" |
513 | source "drivers/misc/cb710/Kconfig" | 513 | source "drivers/misc/cb710/Kconfig" |
514 | source "drivers/misc/iwmc3200top/Kconfig" | ||
515 | source "drivers/misc/ti-st/Kconfig" | 514 | source "drivers/misc/ti-st/Kconfig" |
516 | source "drivers/misc/lis3lv02d/Kconfig" | 515 | source "drivers/misc/lis3lv02d/Kconfig" |
517 | source "drivers/misc/carma/Kconfig" | 516 | source "drivers/misc/carma/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 456972faaeb3..b88df7a350b8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -36,7 +36,6 @@ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o | |||
36 | obj-$(CONFIG_DS1682) += ds1682.o | 36 | obj-$(CONFIG_DS1682) += ds1682.o |
37 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o | 37 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o |
38 | obj-$(CONFIG_C2PORT) += c2port/ | 38 | obj-$(CONFIG_C2PORT) += c2port/ |
39 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ | ||
40 | obj-$(CONFIG_HMC6352) += hmc6352.o | 39 | obj-$(CONFIG_HMC6352) += hmc6352.o |
41 | obj-y += eeprom/ | 40 | obj-y += eeprom/ |
42 | obj-y += cb710/ | 41 | obj-y += cb710/ |
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig deleted file mode 100644 index 9e4b88fb57f1..000000000000 --- a/drivers/misc/iwmc3200top/Kconfig +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | config IWMC3200TOP | ||
2 | tristate "Intel Wireless MultiCom Top Driver" | ||
3 | depends on MMC && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | ---help--- | ||
6 | Intel Wireless MultiCom 3200 Top driver is responsible for | ||
7 | for firmware load and enabled coms enumeration | ||
8 | |||
9 | config IWMC3200TOP_DEBUG | ||
10 | bool "Enable full debug output of iwmc3200top Driver" | ||
11 | depends on IWMC3200TOP | ||
12 | ---help--- | ||
13 | Enable full debug output of iwmc3200top Driver | ||
14 | |||
15 | config IWMC3200TOP_DEBUGFS | ||
16 | bool "Enable Debugfs debugging interface for iwmc3200top" | ||
17 | depends on IWMC3200TOP | ||
18 | ---help--- | ||
19 | Enable creation of debugfs files for iwmc3200top | ||
20 | |||
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile deleted file mode 100644 index fbf53fb4634e..000000000000 --- a/drivers/misc/iwmc3200top/Makefile +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | # iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
2 | # drivers/misc/iwmc3200top/Makefile | ||
3 | # | ||
4 | # Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of the GNU General Public License version | ||
8 | # 2 as published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
18 | # 02110-1301, USA. | ||
19 | # | ||
20 | # | ||
21 | # Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
22 | # - | ||
23 | # | ||
24 | # | ||
25 | |||
26 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o | ||
27 | iwmc3200top-objs := main.o fw-download.o | ||
28 | iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o | ||
29 | iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o | ||
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c deleted file mode 100644 index 62fbaec48207..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.c +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/debufs.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include <linux/mmc/sdio_func.h> | ||
32 | #include <linux/mmc/sdio.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | |||
35 | #include "iwmc3200top.h" | ||
36 | #include "fw-msg.h" | ||
37 | #include "log.h" | ||
38 | #include "debugfs.h" | ||
39 | |||
40 | |||
41 | |||
42 | /* Constants definition */ | ||
43 | #define HEXADECIMAL_RADIX 16 | ||
44 | |||
45 | /* Functions definition */ | ||
46 | |||
47 | |||
48 | #define DEBUGFS_ADD(name, parent) do { \ | ||
49 | dbgfs->dbgfs_##parent##_files.file_##name = \ | ||
50 | debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ | ||
51 | &iwmct_dbgfs_##name##_ops); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define DEBUGFS_RM(name) do { \ | ||
55 | debugfs_remove(name); \ | ||
56 | name = NULL; \ | ||
57 | } while (0) | ||
58 | |||
59 | #define DEBUGFS_READ_FUNC(name) \ | ||
60 | ssize_t iwmct_dbgfs_##name##_read(struct file *file, \ | ||
61 | char __user *user_buf, \ | ||
62 | size_t count, loff_t *ppos); | ||
63 | |||
64 | #define DEBUGFS_WRITE_FUNC(name) \ | ||
65 | ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ | ||
66 | const char __user *user_buf, \ | ||
67 | size_t count, loff_t *ppos); | ||
68 | |||
69 | #define DEBUGFS_READ_FILE_OPS(name) \ | ||
70 | DEBUGFS_READ_FUNC(name) \ | ||
71 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | ||
72 | .read = iwmct_dbgfs_##name##_read, \ | ||
73 | .open = iwmct_dbgfs_open_file_generic, \ | ||
74 | .llseek = generic_file_llseek, \ | ||
75 | }; | ||
76 | |||
77 | #define DEBUGFS_WRITE_FILE_OPS(name) \ | ||
78 | DEBUGFS_WRITE_FUNC(name) \ | ||
79 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | ||
80 | .write = iwmct_dbgfs_##name##_write, \ | ||
81 | .open = iwmct_dbgfs_open_file_generic, \ | ||
82 | .llseek = generic_file_llseek, \ | ||
83 | }; | ||
84 | |||
85 | #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ | ||
86 | DEBUGFS_READ_FUNC(name) \ | ||
87 | DEBUGFS_WRITE_FUNC(name) \ | ||
88 | static const struct file_operations iwmct_dbgfs_##name##_ops = {\ | ||
89 | .write = iwmct_dbgfs_##name##_write, \ | ||
90 | .read = iwmct_dbgfs_##name##_read, \ | ||
91 | .open = iwmct_dbgfs_open_file_generic, \ | ||
92 | .llseek = generic_file_llseek, \ | ||
93 | }; | ||
94 | |||
95 | |||
96 | /* Debugfs file ops definitions */ | ||
97 | |||
98 | /* | ||
99 | * Create the debugfs files and directories | ||
100 | * | ||
101 | */ | ||
102 | void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) | ||
103 | { | ||
104 | struct iwmct_debugfs *dbgfs; | ||
105 | |||
106 | dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL); | ||
107 | if (!dbgfs) { | ||
108 | LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n", | ||
109 | sizeof(struct iwmct_debugfs)); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | priv->dbgfs = dbgfs; | ||
114 | dbgfs->name = name; | ||
115 | dbgfs->dir_drv = debugfs_create_dir(name, NULL); | ||
116 | if (!dbgfs->dir_drv) { | ||
117 | LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n"); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | return; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * Remove the debugfs files and directories | ||
126 | * | ||
127 | */ | ||
128 | void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) | ||
129 | { | ||
130 | if (!dbgfs) | ||
131 | return; | ||
132 | |||
133 | DEBUGFS_RM(dbgfs->dir_drv); | ||
134 | kfree(dbgfs); | ||
135 | dbgfs = NULL; | ||
136 | } | ||
137 | |||
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h deleted file mode 100644 index 71d45759b40f..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/debufs.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __DEBUGFS_H__ | ||
28 | #define __DEBUGFS_H__ | ||
29 | |||
30 | |||
31 | #ifdef CONFIG_IWMC3200TOP_DEBUGFS | ||
32 | |||
33 | struct iwmct_debugfs { | ||
34 | const char *name; | ||
35 | struct dentry *dir_drv; | ||
36 | struct dir_drv_files { | ||
37 | } dbgfs_drv_files; | ||
38 | }; | ||
39 | |||
40 | void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name); | ||
41 | void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs); | ||
42 | |||
43 | #else /* CONFIG_IWMC3200TOP_DEBUGFS */ | ||
44 | |||
45 | struct iwmct_debugfs; | ||
46 | |||
47 | static inline void | ||
48 | iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) | ||
49 | {} | ||
50 | |||
51 | static inline void | ||
52 | iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) | ||
53 | {} | ||
54 | |||
55 | #endif /* CONFIG_IWMC3200TOP_DEBUGFS */ | ||
56 | |||
57 | #endif /* __DEBUGFS_H__ */ | ||
58 | |||
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c deleted file mode 100644 index e27afde6e99f..000000000000 --- a/drivers/misc/iwmc3200top/fw-download.c +++ /dev/null | |||
@@ -1,358 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/fw-download.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/firmware.h> | ||
28 | #include <linux/mmc/sdio_func.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <asm/unaligned.h> | ||
31 | |||
32 | #include "iwmc3200top.h" | ||
33 | #include "log.h" | ||
34 | #include "fw-msg.h" | ||
35 | |||
36 | #define CHECKSUM_BYTES_NUM sizeof(u32) | ||
37 | |||
38 | /** | ||
39 | init parser struct with file | ||
40 | */ | ||
41 | static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, | ||
42 | size_t file_size, size_t block_size) | ||
43 | { | ||
44 | struct iwmct_parser *parser = &priv->parser; | ||
45 | struct iwmct_fw_hdr *fw_hdr = &parser->versions; | ||
46 | |||
47 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
48 | |||
49 | LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); | ||
50 | |||
51 | parser->file = file; | ||
52 | parser->file_size = file_size; | ||
53 | parser->cur_pos = 0; | ||
54 | parser->entry_point = 0; | ||
55 | parser->buf = kzalloc(block_size, GFP_KERNEL); | ||
56 | if (!parser->buf) { | ||
57 | LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | parser->buf_size = block_size; | ||
61 | |||
62 | /* extract fw versions */ | ||
63 | memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr)); | ||
64 | LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n" | ||
65 | "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n", | ||
66 | fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision, | ||
67 | fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision, | ||
68 | fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision, | ||
69 | fw_hdr->tic_name); | ||
70 | |||
71 | parser->cur_pos += sizeof(struct iwmct_fw_hdr); | ||
72 | |||
73 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static bool iwmct_checksum(struct iwmct_priv *priv) | ||
78 | { | ||
79 | struct iwmct_parser *parser = &priv->parser; | ||
80 | __le32 *file = (__le32 *)parser->file; | ||
81 | int i, pad, steps; | ||
82 | u32 accum = 0; | ||
83 | u32 checksum; | ||
84 | u32 mask = 0xffffffff; | ||
85 | |||
86 | pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4; | ||
87 | steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4; | ||
88 | |||
89 | LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps); | ||
90 | |||
91 | for (i = 0; i < steps; i++) | ||
92 | accum += le32_to_cpu(file[i]); | ||
93 | |||
94 | if (pad) { | ||
95 | mask <<= 8 * (4 - pad); | ||
96 | accum += le32_to_cpu(file[steps]) & mask; | ||
97 | } | ||
98 | |||
99 | checksum = get_unaligned_le32((__le32 *)(parser->file + | ||
100 | parser->file_size - CHECKSUM_BYTES_NUM)); | ||
101 | |||
102 | LOG_INFO(priv, FW_DOWNLOAD, | ||
103 | "compare checksum accum=0x%x to checksum=0x%x\n", | ||
104 | accum, checksum); | ||
105 | |||
106 | return checksum == accum; | ||
107 | } | ||
108 | |||
109 | static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, | ||
110 | size_t *sec_size, __le32 *sec_addr) | ||
111 | { | ||
112 | struct iwmct_parser *parser = &priv->parser; | ||
113 | struct iwmct_dbg *dbg = &priv->dbg; | ||
114 | struct iwmct_fw_sec_hdr *sec_hdr; | ||
115 | |||
116 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
117 | |||
118 | while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) | ||
119 | <= parser->file_size) { | ||
120 | |||
121 | sec_hdr = (struct iwmct_fw_sec_hdr *) | ||
122 | (parser->file + parser->cur_pos); | ||
123 | parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr); | ||
124 | |||
125 | LOG_INFO(priv, FW_DOWNLOAD, | ||
126 | "sec hdr: type=%s addr=0x%x size=%d\n", | ||
127 | sec_hdr->type, sec_hdr->target_addr, | ||
128 | sec_hdr->data_size); | ||
129 | |||
130 | if (strcmp(sec_hdr->type, "ENT") == 0) | ||
131 | parser->entry_point = le32_to_cpu(sec_hdr->target_addr); | ||
132 | else if (strcmp(sec_hdr->type, "LBL") == 0) | ||
133 | strcpy(dbg->label_fw, parser->file + parser->cur_pos); | ||
134 | else if (((strcmp(sec_hdr->type, "TOP") == 0) && | ||
135 | (priv->barker & BARKER_DNLOAD_TOP_MSK)) || | ||
136 | ((strcmp(sec_hdr->type, "GPS") == 0) && | ||
137 | (priv->barker & BARKER_DNLOAD_GPS_MSK)) || | ||
138 | ((strcmp(sec_hdr->type, "BTH") == 0) && | ||
139 | (priv->barker & BARKER_DNLOAD_BT_MSK))) { | ||
140 | *sec_addr = sec_hdr->target_addr; | ||
141 | *sec_size = le32_to_cpu(sec_hdr->data_size); | ||
142 | *p_sec = parser->file + parser->cur_pos; | ||
143 | parser->cur_pos += le32_to_cpu(sec_hdr->data_size); | ||
144 | return 1; | ||
145 | } else if (strcmp(sec_hdr->type, "LOG") != 0) | ||
146 | LOG_WARNING(priv, FW_DOWNLOAD, | ||
147 | "skipping section type %s\n", | ||
148 | sec_hdr->type); | ||
149 | |||
150 | parser->cur_pos += le32_to_cpu(sec_hdr->data_size); | ||
151 | LOG_INFO(priv, FW_DOWNLOAD, | ||
152 | "finished with section cur_pos=%zd\n", parser->cur_pos); | ||
153 | } | ||
154 | |||
155 | LOG_TRACE(priv, INIT, "<--\n"); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, | ||
160 | size_t sec_size, __le32 addr) | ||
161 | { | ||
162 | struct iwmct_parser *parser = &priv->parser; | ||
163 | struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; | ||
164 | const u8 *cur_block = p_sec; | ||
165 | size_t sent = 0; | ||
166 | int cnt = 0; | ||
167 | int ret = 0; | ||
168 | u32 cmd = 0; | ||
169 | |||
170 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
171 | LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", | ||
172 | addr, sec_size); | ||
173 | |||
174 | while (sent < sec_size) { | ||
175 | int i; | ||
176 | u32 chksm = 0; | ||
177 | u32 reset = atomic_read(&priv->reset); | ||
178 | /* actual FW data */ | ||
179 | u32 data_size = min(parser->buf_size - sizeof(*hdr), | ||
180 | sec_size - sent); | ||
181 | /* Pad to block size */ | ||
182 | u32 trans_size = (data_size + sizeof(*hdr) + | ||
183 | IWMC_SDIO_BLK_SIZE - 1) & | ||
184 | ~(IWMC_SDIO_BLK_SIZE - 1); | ||
185 | ++cnt; | ||
186 | |||
187 | /* in case of reset, interrupt FW DOWNLAOD */ | ||
188 | if (reset) { | ||
189 | LOG_INFO(priv, FW_DOWNLOAD, | ||
190 | "Reset detected. Abort FW download!!!"); | ||
191 | ret = -ECANCELED; | ||
192 | goto exit; | ||
193 | } | ||
194 | |||
195 | memset(parser->buf, 0, parser->buf_size); | ||
196 | cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS; | ||
197 | cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; | ||
198 | cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS; | ||
199 | cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS; | ||
200 | hdr->data_size = cpu_to_le32(data_size); | ||
201 | hdr->target_addr = addr; | ||
202 | |||
203 | /* checksum is allowed for sizes divisible by 4 */ | ||
204 | if (data_size & 0x3) | ||
205 | cmd &= ~CMD_HDR_USE_CHECKSUM_MSK; | ||
206 | |||
207 | memcpy(hdr->data, cur_block, data_size); | ||
208 | |||
209 | |||
210 | if (cmd & CMD_HDR_USE_CHECKSUM_MSK) { | ||
211 | |||
212 | chksm = data_size + le32_to_cpu(addr) + cmd; | ||
213 | for (i = 0; i < data_size >> 2; i++) | ||
214 | chksm += ((u32 *)cur_block)[i]; | ||
215 | |||
216 | hdr->block_chksm = cpu_to_le32(chksm); | ||
217 | LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n", | ||
218 | hdr->block_chksm); | ||
219 | } | ||
220 | |||
221 | LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, " | ||
222 | "sec_size=%zd, startAddress 0x%X\n", | ||
223 | cnt, trans_size, sent, sec_size, addr); | ||
224 | |||
225 | if (priv->dbg.dump) | ||
226 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size); | ||
227 | |||
228 | |||
229 | hdr->cmd = cpu_to_le32(cmd); | ||
230 | /* send it down */ | ||
231 | /* TODO: add more proper sending and error checking */ | ||
232 | ret = iwmct_tx(priv, parser->buf, trans_size); | ||
233 | if (ret != 0) { | ||
234 | LOG_INFO(priv, FW_DOWNLOAD, | ||
235 | "iwmct_tx returned %d\n", ret); | ||
236 | goto exit; | ||
237 | } | ||
238 | |||
239 | addr = cpu_to_le32(le32_to_cpu(addr) + data_size); | ||
240 | sent += data_size; | ||
241 | cur_block = p_sec + sent; | ||
242 | |||
243 | if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) { | ||
244 | LOG_INFO(priv, FW_DOWNLOAD, | ||
245 | "Block number limit is reached [%d]\n", | ||
246 | priv->dbg.blocks); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | if (sent < sec_size) | ||
252 | ret = -EINVAL; | ||
253 | exit: | ||
254 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) | ||
259 | { | ||
260 | struct iwmct_parser *parser = &priv->parser; | ||
261 | struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; | ||
262 | int ret; | ||
263 | u32 cmd; | ||
264 | |||
265 | LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); | ||
266 | |||
267 | memset(parser->buf, 0, parser->buf_size); | ||
268 | cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; | ||
269 | if (jump) { | ||
270 | cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS; | ||
271 | hdr->target_addr = cpu_to_le32(parser->entry_point); | ||
272 | LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n", | ||
273 | parser->entry_point); | ||
274 | } else { | ||
275 | cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS; | ||
276 | LOG_INFO(priv, FW_DOWNLOAD, "last command\n"); | ||
277 | } | ||
278 | |||
279 | hdr->cmd = cpu_to_le32(cmd); | ||
280 | |||
281 | LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); | ||
282 | /* send it down */ | ||
283 | /* TODO: add more proper sending and error checking */ | ||
284 | ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE); | ||
285 | if (ret) | ||
286 | LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); | ||
287 | |||
288 | LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | int iwmct_fw_load(struct iwmct_priv *priv) | ||
293 | { | ||
294 | const u8 *fw_name = FW_NAME(FW_API_VER); | ||
295 | const struct firmware *raw; | ||
296 | const u8 *pdata; | ||
297 | size_t len; | ||
298 | __le32 addr; | ||
299 | int ret; | ||
300 | |||
301 | |||
302 | LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n", | ||
303 | priv->barker); | ||
304 | LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n", | ||
305 | (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); | ||
306 | LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n", | ||
307 | (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); | ||
308 | LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n", | ||
309 | (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); | ||
310 | |||
311 | |||
312 | /* get the firmware */ | ||
313 | ret = request_firmware(&raw, fw_name, &priv->func->dev); | ||
314 | if (ret < 0) { | ||
315 | LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n", | ||
316 | fw_name, ret); | ||
317 | goto exit; | ||
318 | } | ||
319 | |||
320 | if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) { | ||
321 | LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n", | ||
322 | fw_name, sizeof(struct iwmct_fw_sec_hdr), raw->size); | ||
323 | goto exit; | ||
324 | } | ||
325 | |||
326 | LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); | ||
327 | |||
328 | /* clear parser struct */ | ||
329 | ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); | ||
330 | if (ret < 0) { | ||
331 | LOG_ERROR(priv, FW_DOWNLOAD, | ||
332 | "iwmct_parser_init failed: Reason %d\n", ret); | ||
333 | goto exit; | ||
334 | } | ||
335 | |||
336 | if (!iwmct_checksum(priv)) { | ||
337 | LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); | ||
338 | ret = -EINVAL; | ||
339 | goto exit; | ||
340 | } | ||
341 | |||
342 | /* download firmware to device */ | ||
343 | while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { | ||
344 | ret = iwmct_download_section(priv, pdata, len, addr); | ||
345 | if (ret) { | ||
346 | LOG_ERROR(priv, FW_DOWNLOAD, | ||
347 | "%s download section failed\n", fw_name); | ||
348 | goto exit; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); | ||
353 | |||
354 | exit: | ||
355 | kfree(priv->parser.buf); | ||
356 | release_firmware(raw); | ||
357 | return ret; | ||
358 | } | ||
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h deleted file mode 100644 index 9e26b75bd482..000000000000 --- a/drivers/misc/iwmc3200top/fw-msg.h +++ /dev/null | |||
@@ -1,113 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/fw-msg.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __FWMSG_H__ | ||
28 | #define __FWMSG_H__ | ||
29 | |||
30 | #define COMM_TYPE_D2H 0xFF | ||
31 | #define COMM_TYPE_H2D 0xEE | ||
32 | |||
33 | #define COMM_CATEGORY_OPERATIONAL 0x00 | ||
34 | #define COMM_CATEGORY_DEBUG 0x01 | ||
35 | #define COMM_CATEGORY_TESTABILITY 0x02 | ||
36 | #define COMM_CATEGORY_DIAGNOSTICS 0x03 | ||
37 | |||
38 | #define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A) | ||
39 | |||
40 | #define FW_LOG_SRC_MAX 32 | ||
41 | #define FW_LOG_SRC_ALL 255 | ||
42 | |||
43 | #define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000) | ||
44 | |||
45 | #define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001) | ||
46 | #define CMD_TST_DEV_RESET cpu_to_le16(0x0060) | ||
47 | #define CMD_TST_FUNC_RESET cpu_to_le16(0x0062) | ||
48 | #define CMD_TST_IFACE_RESET cpu_to_le16(0x0064) | ||
49 | #define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065) | ||
50 | #define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080) | ||
51 | #define CMD_TST_WAKEUP cpu_to_le16(0x0081) | ||
52 | #define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082) | ||
53 | #define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083) | ||
54 | #define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096) | ||
55 | |||
56 | #define OP_OPR_ALIVE cpu_to_le16(0x0010) | ||
57 | #define OP_OPR_CMD_ACK cpu_to_le16(0x001F) | ||
58 | #define OP_OPR_CMD_NACK cpu_to_le16(0x0020) | ||
59 | #define OP_TST_MEM_DUMP cpu_to_le16(0x0043) | ||
60 | |||
61 | #define CMD_FLAG_PADDING_256 0x80 | ||
62 | |||
63 | #define FW_HCMD_BLOCK_SIZE 256 | ||
64 | |||
65 | struct msg_hdr { | ||
66 | u8 type; | ||
67 | u8 category; | ||
68 | __le16 opcode; | ||
69 | u8 seqnum; | ||
70 | u8 flags; | ||
71 | __le16 length; | ||
72 | } __attribute__((__packed__)); | ||
73 | |||
74 | struct log_hdr { | ||
75 | __le32 timestamp; | ||
76 | u8 severity; | ||
77 | u8 logsource; | ||
78 | __le16 reserved; | ||
79 | } __attribute__((__packed__)); | ||
80 | |||
81 | struct mdump_hdr { | ||
82 | u8 dmpid; | ||
83 | u8 frag; | ||
84 | __le16 size; | ||
85 | __le32 addr; | ||
86 | } __attribute__((__packed__)); | ||
87 | |||
88 | struct top_msg { | ||
89 | struct msg_hdr hdr; | ||
90 | union { | ||
91 | /* D2H messages */ | ||
92 | struct { | ||
93 | struct log_hdr log_hdr; | ||
94 | u8 data[1]; | ||
95 | } __attribute__((__packed__)) log; | ||
96 | |||
97 | struct { | ||
98 | struct log_hdr log_hdr; | ||
99 | struct mdump_hdr md_hdr; | ||
100 | u8 data[1]; | ||
101 | } __attribute__((__packed__)) mdump; | ||
102 | |||
103 | /* H2D messages */ | ||
104 | struct { | ||
105 | u8 logsource; | ||
106 | u8 sevmask; | ||
107 | } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX]; | ||
108 | struct mdump_hdr mdump_req; | ||
109 | } u; | ||
110 | } __attribute__((__packed__)); | ||
111 | |||
112 | |||
113 | #endif /* __FWMSG_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h deleted file mode 100644 index 620973ed8bf9..000000000000 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/iwmc3200top.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __IWMC3200TOP_H__ | ||
28 | #define __IWMC3200TOP_H__ | ||
29 | |||
30 | #include <linux/workqueue.h> | ||
31 | |||
32 | #define DRV_NAME "iwmc3200top" | ||
33 | #define FW_API_VER 1 | ||
34 | #define _FW_NAME(api) DRV_NAME "." #api ".fw" | ||
35 | #define FW_NAME(api) _FW_NAME(api) | ||
36 | |||
37 | #define IWMC_SDIO_BLK_SIZE 256 | ||
38 | #define IWMC_DEFAULT_TR_BLK 64 | ||
39 | #define IWMC_SDIO_DATA_ADDR 0x0 | ||
40 | #define IWMC_SDIO_INTR_ENABLE_ADDR 0x14 | ||
41 | #define IWMC_SDIO_INTR_STATUS_ADDR 0x13 | ||
42 | #define IWMC_SDIO_INTR_CLEAR_ADDR 0x13 | ||
43 | #define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C | ||
44 | |||
45 | #define COMM_HUB_HEADER_LENGTH 16 | ||
46 | #define LOGGER_HEADER_LENGTH 10 | ||
47 | |||
48 | |||
49 | #define BARKER_DNLOAD_BT_POS 0 | ||
50 | #define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS) | ||
51 | #define BARKER_DNLOAD_GPS_POS 1 | ||
52 | #define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS) | ||
53 | #define BARKER_DNLOAD_TOP_POS 2 | ||
54 | #define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS) | ||
55 | #define BARKER_DNLOAD_RESERVED1_POS 3 | ||
56 | #define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS) | ||
57 | #define BARKER_DNLOAD_JUMP_POS 4 | ||
58 | #define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS) | ||
59 | #define BARKER_DNLOAD_SYNC_POS 5 | ||
60 | #define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS) | ||
61 | #define BARKER_DNLOAD_RESERVED2_POS 6 | ||
62 | #define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS) | ||
63 | #define BARKER_DNLOAD_BARKER_POS 8 | ||
64 | #define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS) | ||
65 | |||
66 | #define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS) | ||
67 | /* whole field barker */ | ||
68 | #define IWMC_BARKER_ACK 0xfeedbabe | ||
69 | |||
70 | #define IWMC_CMD_SIGNATURE 0xcbbc | ||
71 | |||
72 | #define CMD_HDR_OPCODE_POS 0 | ||
73 | #define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS) | ||
74 | #define CMD_HDR_RESPONSE_CODE_POS 4 | ||
75 | #define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS) | ||
76 | #define CMD_HDR_USE_CHECKSUM_POS 8 | ||
77 | #define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS) | ||
78 | #define CMD_HDR_RESPONSE_REQUIRED_POS 9 | ||
79 | #define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS) | ||
80 | #define CMD_HDR_DIRECT_ACCESS_POS 10 | ||
81 | #define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS) | ||
82 | #define CMD_HDR_RESERVED_POS 11 | ||
83 | #define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS) | ||
84 | #define CMD_HDR_SIGNATURE_POS 16 | ||
85 | #define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS) | ||
86 | |||
87 | enum { | ||
88 | IWMC_OPCODE_PING = 0, | ||
89 | IWMC_OPCODE_READ = 1, | ||
90 | IWMC_OPCODE_WRITE = 2, | ||
91 | IWMC_OPCODE_JUMP = 3, | ||
92 | IWMC_OPCODE_REBOOT = 4, | ||
93 | IWMC_OPCODE_PERSISTENT_WRITE = 5, | ||
94 | IWMC_OPCODE_PERSISTENT_READ = 6, | ||
95 | IWMC_OPCODE_READ_MODIFY_WRITE = 7, | ||
96 | IWMC_OPCODE_LAST_COMMAND = 15 | ||
97 | }; | ||
98 | |||
99 | struct iwmct_fw_load_hdr { | ||
100 | __le32 cmd; | ||
101 | __le32 target_addr; | ||
102 | __le32 data_size; | ||
103 | __le32 block_chksm; | ||
104 | u8 data[0]; | ||
105 | }; | ||
106 | |||
107 | /** | ||
108 | * struct iwmct_fw_hdr | ||
109 | * holds all sw components versions | ||
110 | */ | ||
111 | struct iwmct_fw_hdr { | ||
112 | u8 top_major; | ||
113 | u8 top_minor; | ||
114 | u8 top_revision; | ||
115 | u8 gps_major; | ||
116 | u8 gps_minor; | ||
117 | u8 gps_revision; | ||
118 | u8 bt_major; | ||
119 | u8 bt_minor; | ||
120 | u8 bt_revision; | ||
121 | u8 tic_name[31]; | ||
122 | }; | ||
123 | |||
124 | /** | ||
125 | * struct iwmct_fw_sec_hdr | ||
126 | * @type: function type | ||
127 | * @data_size: section's data size | ||
128 | * @target_addr: download address | ||
129 | */ | ||
130 | struct iwmct_fw_sec_hdr { | ||
131 | u8 type[4]; | ||
132 | __le32 data_size; | ||
133 | __le32 target_addr; | ||
134 | }; | ||
135 | |||
136 | /** | ||
137 | * struct iwmct_parser | ||
138 | * @file: fw image | ||
139 | * @file_size: fw size | ||
140 | * @cur_pos: position in file | ||
141 | * @buf: temp buf for download | ||
142 | * @buf_size: size of buf | ||
143 | * @entry_point: address to jump in fw kick-off | ||
144 | */ | ||
145 | struct iwmct_parser { | ||
146 | const u8 *file; | ||
147 | size_t file_size; | ||
148 | size_t cur_pos; | ||
149 | u8 *buf; | ||
150 | size_t buf_size; | ||
151 | u32 entry_point; | ||
152 | struct iwmct_fw_hdr versions; | ||
153 | }; | ||
154 | |||
155 | |||
156 | struct iwmct_work_struct { | ||
157 | struct list_head list; | ||
158 | ssize_t iosize; | ||
159 | }; | ||
160 | |||
161 | struct iwmct_dbg { | ||
162 | int blocks; | ||
163 | bool dump; | ||
164 | bool jump; | ||
165 | bool direct; | ||
166 | bool checksum; | ||
167 | bool fw_download; | ||
168 | int block_size; | ||
169 | int download_trans_blks; | ||
170 | |||
171 | char label_fw[256]; | ||
172 | }; | ||
173 | |||
174 | struct iwmct_debugfs; | ||
175 | |||
176 | struct iwmct_priv { | ||
177 | struct sdio_func *func; | ||
178 | struct iwmct_debugfs *dbgfs; | ||
179 | struct iwmct_parser parser; | ||
180 | atomic_t reset; | ||
181 | atomic_t dev_sync; | ||
182 | u32 trans_len; | ||
183 | u32 barker; | ||
184 | struct iwmct_dbg dbg; | ||
185 | |||
186 | /* drivers work items */ | ||
187 | struct work_struct bus_rescan_worker; | ||
188 | struct work_struct isr_worker; | ||
189 | |||
190 | /* drivers wait queue */ | ||
191 | wait_queue_head_t wait_q; | ||
192 | |||
193 | /* rx request list */ | ||
194 | struct list_head read_req_list; | ||
195 | }; | ||
196 | |||
197 | extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count); | ||
198 | extern int iwmct_fw_load(struct iwmct_priv *priv); | ||
199 | |||
200 | extern void iwmct_dbg_init_params(struct iwmct_priv *drv); | ||
201 | extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv); | ||
202 | extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv); | ||
203 | extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len); | ||
204 | |||
205 | #endif /* __IWMC3200TOP_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c deleted file mode 100644 index a36a55a49cac..000000000000 --- a/drivers/misc/iwmc3200top/log.c +++ /dev/null | |||
@@ -1,348 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/log.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/mmc/sdio_func.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/ctype.h> | ||
31 | #include "fw-msg.h" | ||
32 | #include "iwmc3200top.h" | ||
33 | #include "log.h" | ||
34 | |||
35 | /* Maximal hexadecimal string size of the FW memdump message */ | ||
36 | #define LOG_MSG_SIZE_MAX 12400 | ||
37 | |||
38 | /* iwmct_logdefs is a global used by log macros */ | ||
39 | u8 iwmct_logdefs[LOG_SRC_MAX]; | ||
40 | static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX]; | ||
41 | |||
42 | |||
43 | static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask) | ||
44 | { | ||
45 | int i; | ||
46 | |||
47 | if (src < size) | ||
48 | logdefs[src] = logmask; | ||
49 | else if (src == LOG_SRC_ALL) | ||
50 | for (i = 0; i < size; i++) | ||
51 | logdefs[i] = logmask; | ||
52 | else | ||
53 | return -1; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | int iwmct_log_set_filter(u8 src, u8 logmask) | ||
60 | { | ||
61 | return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask); | ||
62 | } | ||
63 | |||
64 | |||
65 | int iwmct_log_set_fw_filter(u8 src, u8 logmask) | ||
66 | { | ||
67 | return _log_set_log_filter(iwmct_fw_logdefs, | ||
68 | FW_LOG_SRC_MAX, src, logmask); | ||
69 | } | ||
70 | |||
71 | |||
72 | static int log_msg_format_hex(char *str, int slen, u8 *ibuf, | ||
73 | int ilen, char *pref) | ||
74 | { | ||
75 | int pos = 0; | ||
76 | int i; | ||
77 | int len; | ||
78 | |||
79 | for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++) | ||
80 | str[pos] = pref[i]; | ||
81 | |||
82 | for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++) | ||
83 | len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]); | ||
84 | |||
85 | if (i < ilen) | ||
86 | return -1; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* NOTE: This function is not thread safe. | ||
92 | Currently it's called only from sdio rx worker - no race there | ||
93 | */ | ||
94 | void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len) | ||
95 | { | ||
96 | struct top_msg *msg; | ||
97 | static char logbuf[LOG_MSG_SIZE_MAX]; | ||
98 | |||
99 | msg = (struct top_msg *)buf; | ||
100 | |||
101 | if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) { | ||
102 | LOG_ERROR(priv, FW_MSG, "Log message from TOP " | ||
103 | "is too short %d (expected %zd)\n", | ||
104 | len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] & | ||
109 | BIT(msg->u.log.log_hdr.severity)) || | ||
110 | !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity))) | ||
111 | return; | ||
112 | |||
113 | switch (msg->hdr.category) { | ||
114 | case COMM_CATEGORY_TESTABILITY: | ||
115 | if (!(iwmct_logdefs[LOG_SRC_TST] & | ||
116 | BIT(msg->u.log.log_hdr.severity))) | ||
117 | return; | ||
118 | if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, | ||
119 | le16_to_cpu(msg->hdr.length) + | ||
120 | sizeof(msg->hdr), "<TST>")) | ||
121 | LOG_WARNING(priv, TST, | ||
122 | "TOP TST message is too long, truncating..."); | ||
123 | LOG_WARNING(priv, TST, "%s\n", logbuf); | ||
124 | break; | ||
125 | case COMM_CATEGORY_DEBUG: | ||
126 | if (msg->hdr.opcode == OP_DBG_ZSTR_MSG) | ||
127 | LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>", | ||
128 | ((u8 *)msg) + sizeof(msg->hdr) | ||
129 | + sizeof(msg->u.log.log_hdr)); | ||
130 | else { | ||
131 | if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, | ||
132 | le16_to_cpu(msg->hdr.length) | ||
133 | + sizeof(msg->hdr), | ||
134 | "<DBG>")) | ||
135 | LOG_WARNING(priv, FW_MSG, | ||
136 | "TOP DBG message is too long," | ||
137 | "truncating..."); | ||
138 | LOG_WARNING(priv, FW_MSG, "%s\n", logbuf); | ||
139 | } | ||
140 | break; | ||
141 | default: | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size) | ||
147 | { | ||
148 | int i, pos, len; | ||
149 | for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) { | ||
150 | len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,", | ||
151 | i, logdefs[i]); | ||
152 | pos += len; | ||
153 | } | ||
154 | buf[pos-1] = '\n'; | ||
155 | buf[pos] = '\0'; | ||
156 | |||
157 | if (i < logdefsz) | ||
158 | return -1; | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | int log_get_filter_str(char *buf, int size) | ||
163 | { | ||
164 | return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size); | ||
165 | } | ||
166 | |||
167 | int log_get_fw_filter_str(char *buf, int size) | ||
168 | { | ||
169 | return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size); | ||
170 | } | ||
171 | |||
172 | #define HEXADECIMAL_RADIX 16 | ||
173 | #define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */ | ||
174 | |||
175 | ssize_t show_iwmct_log_level(struct device *d, | ||
176 | struct device_attribute *attr, char *buf) | ||
177 | { | ||
178 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
179 | char *str_buf; | ||
180 | int buf_size; | ||
181 | ssize_t ret; | ||
182 | |||
183 | buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1; | ||
184 | str_buf = kzalloc(buf_size, GFP_KERNEL); | ||
185 | if (!str_buf) { | ||
186 | LOG_ERROR(priv, DEBUGFS, | ||
187 | "failed to allocate %d bytes\n", buf_size); | ||
188 | ret = -ENOMEM; | ||
189 | goto exit; | ||
190 | } | ||
191 | |||
192 | if (log_get_filter_str(str_buf, buf_size) < 0) { | ||
193 | ret = -EINVAL; | ||
194 | goto exit; | ||
195 | } | ||
196 | |||
197 | ret = sprintf(buf, "%s", str_buf); | ||
198 | |||
199 | exit: | ||
200 | kfree(str_buf); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | ssize_t store_iwmct_log_level(struct device *d, | ||
205 | struct device_attribute *attr, | ||
206 | const char *buf, size_t count) | ||
207 | { | ||
208 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
209 | char *token, *str_buf = NULL; | ||
210 | long val; | ||
211 | ssize_t ret = count; | ||
212 | u8 src, mask; | ||
213 | |||
214 | if (!count) | ||
215 | goto exit; | ||
216 | |||
217 | str_buf = kzalloc(count, GFP_KERNEL); | ||
218 | if (!str_buf) { | ||
219 | LOG_ERROR(priv, DEBUGFS, | ||
220 | "failed to allocate %zd bytes\n", count); | ||
221 | ret = -ENOMEM; | ||
222 | goto exit; | ||
223 | } | ||
224 | |||
225 | memcpy(str_buf, buf, count); | ||
226 | |||
227 | while ((token = strsep(&str_buf, ",")) != NULL) { | ||
228 | while (isspace(*token)) | ||
229 | ++token; | ||
230 | if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { | ||
231 | LOG_ERROR(priv, DEBUGFS, | ||
232 | "failed to convert string to long %s\n", | ||
233 | token); | ||
234 | ret = -EINVAL; | ||
235 | goto exit; | ||
236 | } | ||
237 | |||
238 | mask = val & 0xFF; | ||
239 | src = (val & 0XFF00) >> 8; | ||
240 | iwmct_log_set_filter(src, mask); | ||
241 | } | ||
242 | |||
243 | exit: | ||
244 | kfree(str_buf); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | ssize_t show_iwmct_log_level_fw(struct device *d, | ||
249 | struct device_attribute *attr, char *buf) | ||
250 | { | ||
251 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
252 | char *str_buf; | ||
253 | int buf_size; | ||
254 | ssize_t ret; | ||
255 | |||
256 | buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2; | ||
257 | |||
258 | str_buf = kzalloc(buf_size, GFP_KERNEL); | ||
259 | if (!str_buf) { | ||
260 | LOG_ERROR(priv, DEBUGFS, | ||
261 | "failed to allocate %d bytes\n", buf_size); | ||
262 | ret = -ENOMEM; | ||
263 | goto exit; | ||
264 | } | ||
265 | |||
266 | if (log_get_fw_filter_str(str_buf, buf_size) < 0) { | ||
267 | ret = -EINVAL; | ||
268 | goto exit; | ||
269 | } | ||
270 | |||
271 | ret = sprintf(buf, "%s", str_buf); | ||
272 | |||
273 | exit: | ||
274 | kfree(str_buf); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | ssize_t store_iwmct_log_level_fw(struct device *d, | ||
279 | struct device_attribute *attr, | ||
280 | const char *buf, size_t count) | ||
281 | { | ||
282 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
283 | struct top_msg cmd; | ||
284 | char *token, *str_buf = NULL; | ||
285 | ssize_t ret = count; | ||
286 | u16 cmdlen = 0; | ||
287 | int i; | ||
288 | long val; | ||
289 | u8 src, mask; | ||
290 | |||
291 | if (!count) | ||
292 | goto exit; | ||
293 | |||
294 | str_buf = kzalloc(count, GFP_KERNEL); | ||
295 | if (!str_buf) { | ||
296 | LOG_ERROR(priv, DEBUGFS, | ||
297 | "failed to allocate %zd bytes\n", count); | ||
298 | ret = -ENOMEM; | ||
299 | goto exit; | ||
300 | } | ||
301 | |||
302 | memcpy(str_buf, buf, count); | ||
303 | |||
304 | cmd.hdr.type = COMM_TYPE_H2D; | ||
305 | cmd.hdr.category = COMM_CATEGORY_DEBUG; | ||
306 | cmd.hdr.opcode = CMD_DBG_LOG_LEVEL; | ||
307 | |||
308 | for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) && | ||
309 | (i < FW_LOG_SRC_MAX); i++) { | ||
310 | |||
311 | while (isspace(*token)) | ||
312 | ++token; | ||
313 | |||
314 | if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { | ||
315 | LOG_ERROR(priv, DEBUGFS, | ||
316 | "failed to convert string to long %s\n", | ||
317 | token); | ||
318 | ret = -EINVAL; | ||
319 | goto exit; | ||
320 | } | ||
321 | |||
322 | mask = val & 0xFF; /* LSB */ | ||
323 | src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */ | ||
324 | iwmct_log_set_fw_filter(src, mask); | ||
325 | |||
326 | cmd.u.logdefs[i].logsource = src; | ||
327 | cmd.u.logdefs[i].sevmask = mask; | ||
328 | } | ||
329 | |||
330 | cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0])); | ||
331 | cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr)); | ||
332 | |||
333 | ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen); | ||
334 | if (ret) { | ||
335 | LOG_ERROR(priv, DEBUGFS, | ||
336 | "Failed to send %d bytes of fwcmd, ret=%zd\n", | ||
337 | cmdlen, ret); | ||
338 | goto exit; | ||
339 | } else | ||
340 | LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen); | ||
341 | |||
342 | ret = count; | ||
343 | |||
344 | exit: | ||
345 | kfree(str_buf); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h deleted file mode 100644 index 4434bb16cea7..000000000000 --- a/drivers/misc/iwmc3200top/log.h +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/log.h | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __LOG_H__ | ||
28 | #define __LOG_H__ | ||
29 | |||
30 | |||
31 | /* log severity: | ||
32 | * The log levels here match FW log levels | ||
33 | * so values need to stay as is */ | ||
34 | #define LOG_SEV_CRITICAL 0 | ||
35 | #define LOG_SEV_ERROR 1 | ||
36 | #define LOG_SEV_WARNING 2 | ||
37 | #define LOG_SEV_INFO 3 | ||
38 | #define LOG_SEV_INFOEX 4 | ||
39 | |||
40 | /* Log levels not defined for FW */ | ||
41 | #define LOG_SEV_TRACE 5 | ||
42 | #define LOG_SEV_DUMP 6 | ||
43 | |||
44 | #define LOG_SEV_FW_FILTER_ALL \ | ||
45 | (BIT(LOG_SEV_CRITICAL) | \ | ||
46 | BIT(LOG_SEV_ERROR) | \ | ||
47 | BIT(LOG_SEV_WARNING) | \ | ||
48 | BIT(LOG_SEV_INFO) | \ | ||
49 | BIT(LOG_SEV_INFOEX)) | ||
50 | |||
51 | #define LOG_SEV_FILTER_ALL \ | ||
52 | (BIT(LOG_SEV_CRITICAL) | \ | ||
53 | BIT(LOG_SEV_ERROR) | \ | ||
54 | BIT(LOG_SEV_WARNING) | \ | ||
55 | BIT(LOG_SEV_INFO) | \ | ||
56 | BIT(LOG_SEV_INFOEX) | \ | ||
57 | BIT(LOG_SEV_TRACE) | \ | ||
58 | BIT(LOG_SEV_DUMP)) | ||
59 | |||
60 | /* log source */ | ||
61 | #define LOG_SRC_INIT 0 | ||
62 | #define LOG_SRC_DEBUGFS 1 | ||
63 | #define LOG_SRC_FW_DOWNLOAD 2 | ||
64 | #define LOG_SRC_FW_MSG 3 | ||
65 | #define LOG_SRC_TST 4 | ||
66 | #define LOG_SRC_IRQ 5 | ||
67 | |||
68 | #define LOG_SRC_MAX 6 | ||
69 | #define LOG_SRC_ALL 0xFF | ||
70 | |||
71 | /** | ||
72 | * Default intitialization runtime log level | ||
73 | */ | ||
74 | #ifndef LOG_SEV_FILTER_RUNTIME | ||
75 | #define LOG_SEV_FILTER_RUNTIME \ | ||
76 | (BIT(LOG_SEV_CRITICAL) | \ | ||
77 | BIT(LOG_SEV_ERROR) | \ | ||
78 | BIT(LOG_SEV_WARNING)) | ||
79 | #endif | ||
80 | |||
81 | #ifndef FW_LOG_SEV_FILTER_RUNTIME | ||
82 | #define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL | ||
83 | #endif | ||
84 | |||
85 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
86 | /** | ||
87 | * Log macros | ||
88 | */ | ||
89 | |||
90 | #define priv2dev(priv) (&(priv->func)->dev) | ||
91 | |||
92 | #define LOG_CRITICAL(priv, src, fmt, args...) \ | ||
93 | do { \ | ||
94 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \ | ||
95 | dev_crit(priv2dev(priv), "%s %d: " fmt, \ | ||
96 | __func__, __LINE__, ##args); \ | ||
97 | } while (0) | ||
98 | |||
99 | #define LOG_ERROR(priv, src, fmt, args...) \ | ||
100 | do { \ | ||
101 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \ | ||
102 | dev_err(priv2dev(priv), "%s %d: " fmt, \ | ||
103 | __func__, __LINE__, ##args); \ | ||
104 | } while (0) | ||
105 | |||
106 | #define LOG_WARNING(priv, src, fmt, args...) \ | ||
107 | do { \ | ||
108 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \ | ||
109 | dev_warn(priv2dev(priv), "%s %d: " fmt, \ | ||
110 | __func__, __LINE__, ##args); \ | ||
111 | } while (0) | ||
112 | |||
113 | #define LOG_INFO(priv, src, fmt, args...) \ | ||
114 | do { \ | ||
115 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \ | ||
116 | dev_info(priv2dev(priv), "%s %d: " fmt, \ | ||
117 | __func__, __LINE__, ##args); \ | ||
118 | } while (0) | ||
119 | |||
120 | #define LOG_TRACE(priv, src, fmt, args...) \ | ||
121 | do { \ | ||
122 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \ | ||
123 | dev_dbg(priv2dev(priv), "%s %d: " fmt, \ | ||
124 | __func__, __LINE__, ##args); \ | ||
125 | } while (0) | ||
126 | |||
127 | #define LOG_HEXDUMP(src, ptr, len) \ | ||
128 | do { \ | ||
129 | if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \ | ||
130 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ | ||
131 | 16, 1, ptr, len, false); \ | ||
132 | } while (0) | ||
133 | |||
134 | void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len); | ||
135 | |||
136 | extern u8 iwmct_logdefs[]; | ||
137 | |||
138 | int iwmct_log_set_filter(u8 src, u8 logmask); | ||
139 | int iwmct_log_set_fw_filter(u8 src, u8 logmask); | ||
140 | |||
141 | ssize_t show_iwmct_log_level(struct device *d, | ||
142 | struct device_attribute *attr, char *buf); | ||
143 | ssize_t store_iwmct_log_level(struct device *d, | ||
144 | struct device_attribute *attr, | ||
145 | const char *buf, size_t count); | ||
146 | ssize_t show_iwmct_log_level_fw(struct device *d, | ||
147 | struct device_attribute *attr, char *buf); | ||
148 | ssize_t store_iwmct_log_level_fw(struct device *d, | ||
149 | struct device_attribute *attr, | ||
150 | const char *buf, size_t count); | ||
151 | |||
152 | #else | ||
153 | |||
154 | #define LOG_CRITICAL(priv, src, fmt, args...) | ||
155 | #define LOG_ERROR(priv, src, fmt, args...) | ||
156 | #define LOG_WARNING(priv, src, fmt, args...) | ||
157 | #define LOG_INFO(priv, src, fmt, args...) | ||
158 | #define LOG_TRACE(priv, src, fmt, args...) | ||
159 | #define LOG_HEXDUMP(src, ptr, len) | ||
160 | |||
161 | static inline void iwmct_log_top_message(struct iwmct_priv *priv, | ||
162 | u8 *buf, int len) {} | ||
163 | static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; } | ||
164 | static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; } | ||
165 | |||
166 | #endif /* CONFIG_IWMC3200TOP_DEBUG */ | ||
167 | |||
168 | int log_get_filter_str(char *buf, int size); | ||
169 | int log_get_fw_filter_str(char *buf, int size); | ||
170 | |||
171 | #endif /* __LOG_H__ */ | ||
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c deleted file mode 100644 index 701eb600b127..000000000000 --- a/drivers/misc/iwmc3200top/main.c +++ /dev/null | |||
@@ -1,662 +0,0 @@ | |||
1 | /* | ||
2 | * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver | ||
3 | * drivers/misc/iwmc3200top/main.c | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> | ||
23 | * - | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/debugfs.h> | ||
32 | #include <linux/mmc/sdio_ids.h> | ||
33 | #include <linux/mmc/sdio_func.h> | ||
34 | #include <linux/mmc/sdio.h> | ||
35 | |||
36 | #include "iwmc3200top.h" | ||
37 | #include "log.h" | ||
38 | #include "fw-msg.h" | ||
39 | #include "debugfs.h" | ||
40 | |||
41 | |||
42 | #define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver" | ||
43 | #define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation." | ||
44 | |||
45 | #define DRIVER_VERSION "0.1.62" | ||
46 | |||
47 | MODULE_DESCRIPTION(DRIVER_DESCRIPTION); | ||
48 | MODULE_VERSION(DRIVER_VERSION); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | MODULE_AUTHOR(DRIVER_COPYRIGHT); | ||
51 | MODULE_FIRMWARE(FW_NAME(FW_API_VER)); | ||
52 | |||
53 | |||
54 | static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
55 | { | ||
56 | return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count); | ||
57 | |||
58 | } | ||
59 | int iwmct_tx(struct iwmct_priv *priv, void *src, int count) | ||
60 | { | ||
61 | int ret; | ||
62 | sdio_claim_host(priv->func); | ||
63 | ret = __iwmct_tx(priv, src, count); | ||
64 | sdio_release_host(priv->func); | ||
65 | return ret; | ||
66 | } | ||
67 | /* | ||
68 | * This workers main task is to wait for OP_OPR_ALIVE | ||
69 | * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. | ||
70 | * When OP_OPR_ALIVE received it will issue | ||
71 | * a call to "bus_rescan_devices". | ||
72 | */ | ||
73 | static void iwmct_rescan_worker(struct work_struct *ws) | ||
74 | { | ||
75 | struct iwmct_priv *priv; | ||
76 | int ret; | ||
77 | |||
78 | priv = container_of(ws, struct iwmct_priv, bus_rescan_worker); | ||
79 | |||
80 | LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n"); | ||
81 | |||
82 | ret = bus_rescan_devices(priv->func->dev.bus); | ||
83 | if (ret < 0) | ||
84 | LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n"); | ||
85 | } | ||
86 | |||
87 | static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) | ||
88 | { | ||
89 | switch (msg->hdr.opcode) { | ||
90 | case OP_OPR_ALIVE: | ||
91 | LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n"); | ||
92 | schedule_work(&priv->bus_rescan_worker); | ||
93 | break; | ||
94 | default: | ||
95 | LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n", | ||
96 | msg->hdr.opcode); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len) | ||
103 | { | ||
104 | struct top_msg *msg; | ||
105 | |||
106 | msg = (struct top_msg *)buf; | ||
107 | |||
108 | if (msg->hdr.type != COMM_TYPE_D2H) { | ||
109 | LOG_ERROR(priv, FW_MSG, | ||
110 | "Message from TOP with invalid message type 0x%X\n", | ||
111 | msg->hdr.type); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | if (len < sizeof(msg->hdr)) { | ||
116 | LOG_ERROR(priv, FW_MSG, | ||
117 | "Message from TOP is too short for message header " | ||
118 | "received %d bytes, expected at least %zd bytes\n", | ||
119 | len, sizeof(msg->hdr)); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) { | ||
124 | LOG_ERROR(priv, FW_MSG, | ||
125 | "Message length (%d bytes) is shorter than " | ||
126 | "in header (%d bytes)\n", | ||
127 | len, le16_to_cpu(msg->hdr.length)); | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | switch (msg->hdr.category) { | ||
132 | case COMM_CATEGORY_OPERATIONAL: | ||
133 | op_top_message(priv, (struct top_msg *)buf); | ||
134 | break; | ||
135 | |||
136 | case COMM_CATEGORY_DEBUG: | ||
137 | case COMM_CATEGORY_TESTABILITY: | ||
138 | case COMM_CATEGORY_DIAGNOSTICS: | ||
139 | iwmct_log_top_message(priv, buf, len); | ||
140 | break; | ||
141 | |||
142 | default: | ||
143 | LOG_ERROR(priv, FW_MSG, | ||
144 | "Message from TOP with unknown category 0x%X\n", | ||
145 | msg->hdr.category); | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) | ||
151 | { | ||
152 | int ret; | ||
153 | u8 *buf; | ||
154 | |||
155 | LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n"); | ||
156 | |||
157 | /* add padding to 256 for IWMC */ | ||
158 | ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; | ||
159 | |||
160 | LOG_HEXDUMP(FW_MSG, cmd, len); | ||
161 | |||
162 | if (len > FW_HCMD_BLOCK_SIZE) { | ||
163 | LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n", | ||
164 | len, FW_HCMD_BLOCK_SIZE); | ||
165 | return -1; | ||
166 | } | ||
167 | |||
168 | buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL); | ||
169 | if (!buf) { | ||
170 | LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n", | ||
171 | FW_HCMD_BLOCK_SIZE); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | memcpy(buf, cmd, len); | ||
176 | ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE); | ||
177 | |||
178 | kfree(buf); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | |||
183 | static void iwmct_irq_read_worker(struct work_struct *ws) | ||
184 | { | ||
185 | struct iwmct_priv *priv; | ||
186 | struct iwmct_work_struct *read_req; | ||
187 | __le32 *buf = NULL; | ||
188 | int ret; | ||
189 | int iosize; | ||
190 | u32 barker; | ||
191 | bool is_barker; | ||
192 | |||
193 | priv = container_of(ws, struct iwmct_priv, isr_worker); | ||
194 | |||
195 | LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); | ||
196 | |||
197 | /* --------------------- Handshake with device -------------------- */ | ||
198 | sdio_claim_host(priv->func); | ||
199 | |||
200 | /* all list manipulations have to be protected by | ||
201 | * sdio_claim_host/sdio_release_host */ | ||
202 | if (list_empty(&priv->read_req_list)) { | ||
203 | LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n"); | ||
204 | goto exit_release; | ||
205 | } | ||
206 | |||
207 | read_req = list_entry(priv->read_req_list.next, | ||
208 | struct iwmct_work_struct, list); | ||
209 | |||
210 | list_del(&read_req->list); | ||
211 | iosize = read_req->iosize; | ||
212 | kfree(read_req); | ||
213 | |||
214 | buf = kzalloc(iosize, GFP_KERNEL); | ||
215 | if (!buf) { | ||
216 | LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize); | ||
217 | goto exit_release; | ||
218 | } | ||
219 | |||
220 | LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n", | ||
221 | iosize, buf, priv->func->num); | ||
222 | |||
223 | /* read from device */ | ||
224 | ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize); | ||
225 | if (ret) { | ||
226 | LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret); | ||
227 | goto exit_release; | ||
228 | } | ||
229 | |||
230 | LOG_HEXDUMP(IRQ, (u8 *)buf, iosize); | ||
231 | |||
232 | barker = le32_to_cpu(buf[0]); | ||
233 | |||
234 | /* Verify whether it's a barker and if not - treat as regular Rx */ | ||
235 | if (barker == IWMC_BARKER_ACK || | ||
236 | (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) { | ||
237 | |||
238 | /* Valid Barker is equal on first 4 dwords */ | ||
239 | is_barker = (buf[1] == buf[0]) && | ||
240 | (buf[2] == buf[0]) && | ||
241 | (buf[3] == buf[0]); | ||
242 | |||
243 | if (!is_barker) { | ||
244 | LOG_WARNING(priv, IRQ, | ||
245 | "Potentially inconsistent barker " | ||
246 | "%08X_%08X_%08X_%08X\n", | ||
247 | le32_to_cpu(buf[0]), le32_to_cpu(buf[1]), | ||
248 | le32_to_cpu(buf[2]), le32_to_cpu(buf[3])); | ||
249 | } | ||
250 | } else { | ||
251 | is_barker = false; | ||
252 | } | ||
253 | |||
254 | /* Handle Top CommHub message */ | ||
255 | if (!is_barker) { | ||
256 | sdio_release_host(priv->func); | ||
257 | handle_top_message(priv, (u8 *)buf, iosize); | ||
258 | goto exit; | ||
259 | } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */ | ||
260 | if (atomic_read(&priv->dev_sync) == 0) { | ||
261 | LOG_ERROR(priv, IRQ, | ||
262 | "ACK barker arrived out-of-sync\n"); | ||
263 | goto exit_release; | ||
264 | } | ||
265 | |||
266 | /* Continuing to FW download (after Sync is completed)*/ | ||
267 | atomic_set(&priv->dev_sync, 0); | ||
268 | LOG_INFO(priv, IRQ, "ACK barker arrived " | ||
269 | "- starting FW download\n"); | ||
270 | } else { /* REBOOT barker */ | ||
271 | LOG_INFO(priv, IRQ, "Received reboot barker: %x\n", barker); | ||
272 | priv->barker = barker; | ||
273 | |||
274 | if (barker & BARKER_DNLOAD_SYNC_MSK) { | ||
275 | /* Send the same barker back */ | ||
276 | ret = __iwmct_tx(priv, buf, iosize); | ||
277 | if (ret) { | ||
278 | LOG_ERROR(priv, IRQ, | ||
279 | "error %d echoing barker\n", ret); | ||
280 | goto exit_release; | ||
281 | } | ||
282 | LOG_INFO(priv, IRQ, "Echoing barker to device\n"); | ||
283 | atomic_set(&priv->dev_sync, 1); | ||
284 | goto exit_release; | ||
285 | } | ||
286 | |||
287 | /* Continuing to FW download (without Sync) */ | ||
288 | LOG_INFO(priv, IRQ, "No sync requested " | ||
289 | "- starting FW download\n"); | ||
290 | } | ||
291 | |||
292 | sdio_release_host(priv->func); | ||
293 | |||
294 | if (priv->dbg.fw_download) | ||
295 | iwmct_fw_load(priv); | ||
296 | else | ||
297 | LOG_ERROR(priv, IRQ, "FW download not allowed\n"); | ||
298 | |||
299 | goto exit; | ||
300 | |||
301 | exit_release: | ||
302 | sdio_release_host(priv->func); | ||
303 | exit: | ||
304 | kfree(buf); | ||
305 | LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n"); | ||
306 | } | ||
307 | |||
308 | static void iwmct_irq(struct sdio_func *func) | ||
309 | { | ||
310 | struct iwmct_priv *priv; | ||
311 | int val, ret; | ||
312 | int iosize; | ||
313 | int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR; | ||
314 | struct iwmct_work_struct *read_req; | ||
315 | |||
316 | priv = sdio_get_drvdata(func); | ||
317 | |||
318 | LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); | ||
319 | |||
320 | /* read the function's status register */ | ||
321 | val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); | ||
322 | |||
323 | LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); | ||
324 | |||
325 | if (!val) { | ||
326 | LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); | ||
327 | goto exit_clear_intr; | ||
328 | } | ||
329 | |||
330 | |||
331 | /* | ||
332 | * read 2 bytes of the transaction size | ||
333 | * IMPORTANT: sdio transaction size has to be read before clearing | ||
334 | * sdio interrupt!!! | ||
335 | */ | ||
336 | val = sdio_readb(priv->func, addr++, &ret); | ||
337 | iosize = val; | ||
338 | val = sdio_readb(priv->func, addr++, &ret); | ||
339 | iosize += val << 8; | ||
340 | |||
341 | LOG_INFO(priv, IRQ, "READ size %d\n", iosize); | ||
342 | |||
343 | if (iosize == 0) { | ||
344 | LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize); | ||
345 | goto exit_clear_intr; | ||
346 | } | ||
347 | |||
348 | /* allocate a work structure to pass iosize to the worker */ | ||
349 | read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL); | ||
350 | if (!read_req) { | ||
351 | LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n"); | ||
352 | goto exit_clear_intr; | ||
353 | } | ||
354 | |||
355 | INIT_LIST_HEAD(&read_req->list); | ||
356 | read_req->iosize = iosize; | ||
357 | |||
358 | list_add_tail(&priv->read_req_list, &read_req->list); | ||
359 | |||
360 | /* clear the function's interrupt request bit (write 1 to clear) */ | ||
361 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); | ||
362 | |||
363 | schedule_work(&priv->isr_worker); | ||
364 | |||
365 | LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); | ||
366 | |||
367 | return; | ||
368 | |||
369 | exit_clear_intr: | ||
370 | /* clear the function's interrupt request bit (write 1 to clear) */ | ||
371 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); | ||
372 | } | ||
373 | |||
374 | |||
375 | static int blocks; | ||
376 | module_param(blocks, int, 0604); | ||
377 | MODULE_PARM_DESC(blocks, "max_blocks_to_send"); | ||
378 | |||
379 | static bool dump; | ||
380 | module_param(dump, bool, 0604); | ||
381 | MODULE_PARM_DESC(dump, "dump_hex_content"); | ||
382 | |||
383 | static bool jump = 1; | ||
384 | module_param(jump, bool, 0604); | ||
385 | |||
386 | static bool direct = 1; | ||
387 | module_param(direct, bool, 0604); | ||
388 | |||
389 | static bool checksum = 1; | ||
390 | module_param(checksum, bool, 0604); | ||
391 | |||
392 | static bool fw_download = 1; | ||
393 | module_param(fw_download, bool, 0604); | ||
394 | |||
395 | static int block_size = IWMC_SDIO_BLK_SIZE; | ||
396 | module_param(block_size, int, 0404); | ||
397 | |||
398 | static int download_trans_blks = IWMC_DEFAULT_TR_BLK; | ||
399 | module_param(download_trans_blks, int, 0604); | ||
400 | |||
401 | static bool rubbish_barker; | ||
402 | module_param(rubbish_barker, bool, 0604); | ||
403 | |||
404 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
405 | static int log_level[LOG_SRC_MAX]; | ||
406 | static unsigned int log_level_argc; | ||
407 | module_param_array(log_level, int, &log_level_argc, 0604); | ||
408 | MODULE_PARM_DESC(log_level, "log_level"); | ||
409 | |||
410 | static int log_level_fw[FW_LOG_SRC_MAX]; | ||
411 | static unsigned int log_level_fw_argc; | ||
412 | module_param_array(log_level_fw, int, &log_level_fw_argc, 0604); | ||
413 | MODULE_PARM_DESC(log_level_fw, "log_level_fw"); | ||
414 | #endif | ||
415 | |||
416 | void iwmct_dbg_init_params(struct iwmct_priv *priv) | ||
417 | { | ||
418 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
419 | int i; | ||
420 | |||
421 | for (i = 0; i < log_level_argc; i++) { | ||
422 | dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n", | ||
423 | i, log_level[i]); | ||
424 | iwmct_log_set_filter((log_level[i] >> 8) & 0xFF, | ||
425 | log_level[i] & 0xFF); | ||
426 | } | ||
427 | for (i = 0; i < log_level_fw_argc; i++) { | ||
428 | dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n", | ||
429 | i, log_level_fw[i]); | ||
430 | iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF, | ||
431 | log_level_fw[i] & 0xFF); | ||
432 | } | ||
433 | #endif | ||
434 | |||
435 | priv->dbg.blocks = blocks; | ||
436 | LOG_INFO(priv, INIT, "blocks=%d\n", blocks); | ||
437 | priv->dbg.dump = (bool)dump; | ||
438 | LOG_INFO(priv, INIT, "dump=%d\n", dump); | ||
439 | priv->dbg.jump = (bool)jump; | ||
440 | LOG_INFO(priv, INIT, "jump=%d\n", jump); | ||
441 | priv->dbg.direct = (bool)direct; | ||
442 | LOG_INFO(priv, INIT, "direct=%d\n", direct); | ||
443 | priv->dbg.checksum = (bool)checksum; | ||
444 | LOG_INFO(priv, INIT, "checksum=%d\n", checksum); | ||
445 | priv->dbg.fw_download = (bool)fw_download; | ||
446 | LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download); | ||
447 | priv->dbg.block_size = block_size; | ||
448 | LOG_INFO(priv, INIT, "block_size=%d\n", block_size); | ||
449 | priv->dbg.download_trans_blks = download_trans_blks; | ||
450 | LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks); | ||
451 | } | ||
452 | |||
453 | /***************************************************************************** | ||
454 | * | ||
455 | * sysfs attributes | ||
456 | * | ||
457 | *****************************************************************************/ | ||
458 | static ssize_t show_iwmct_fw_version(struct device *d, | ||
459 | struct device_attribute *attr, char *buf) | ||
460 | { | ||
461 | struct iwmct_priv *priv = dev_get_drvdata(d); | ||
462 | return sprintf(buf, "%s\n", priv->dbg.label_fw); | ||
463 | } | ||
464 | static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL); | ||
465 | |||
466 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
467 | static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO, | ||
468 | show_iwmct_log_level, store_iwmct_log_level); | ||
469 | static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO, | ||
470 | show_iwmct_log_level_fw, store_iwmct_log_level_fw); | ||
471 | #endif | ||
472 | |||
473 | static struct attribute *iwmct_sysfs_entries[] = { | ||
474 | &dev_attr_cc_label_fw.attr, | ||
475 | #ifdef CONFIG_IWMC3200TOP_DEBUG | ||
476 | &dev_attr_log_level.attr, | ||
477 | &dev_attr_log_level_fw.attr, | ||
478 | #endif | ||
479 | NULL | ||
480 | }; | ||
481 | |||
482 | static struct attribute_group iwmct_attribute_group = { | ||
483 | .name = NULL, /* put in device directory */ | ||
484 | .attrs = iwmct_sysfs_entries, | ||
485 | }; | ||
486 | |||
487 | |||
488 | static int iwmct_probe(struct sdio_func *func, | ||
489 | const struct sdio_device_id *id) | ||
490 | { | ||
491 | struct iwmct_priv *priv; | ||
492 | int ret; | ||
493 | int val = 1; | ||
494 | int addr = IWMC_SDIO_INTR_ENABLE_ADDR; | ||
495 | |||
496 | dev_dbg(&func->dev, "enter iwmct_probe\n"); | ||
497 | |||
498 | dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n", | ||
499 | jiffies_to_msecs(2147483647), HZ); | ||
500 | |||
501 | priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL); | ||
502 | if (!priv) { | ||
503 | dev_err(&func->dev, "kzalloc error\n"); | ||
504 | return -ENOMEM; | ||
505 | } | ||
506 | priv->func = func; | ||
507 | sdio_set_drvdata(func, priv); | ||
508 | |||
509 | INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker); | ||
510 | INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker); | ||
511 | |||
512 | init_waitqueue_head(&priv->wait_q); | ||
513 | |||
514 | sdio_claim_host(func); | ||
515 | /* FIXME: Remove after it is fixed in the Boot ROM upgrade */ | ||
516 | func->enable_timeout = 10; | ||
517 | |||
518 | /* In our HW, setting the block size also wakes up the boot rom. */ | ||
519 | ret = sdio_set_block_size(func, priv->dbg.block_size); | ||
520 | if (ret) { | ||
521 | LOG_ERROR(priv, INIT, | ||
522 | "sdio_set_block_size() failure: %d\n", ret); | ||
523 | goto error_sdio_enable; | ||
524 | } | ||
525 | |||
526 | ret = sdio_enable_func(func); | ||
527 | if (ret) { | ||
528 | LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret); | ||
529 | goto error_sdio_enable; | ||
530 | } | ||
531 | |||
532 | /* init reset and dev_sync states */ | ||
533 | atomic_set(&priv->reset, 0); | ||
534 | atomic_set(&priv->dev_sync, 0); | ||
535 | |||
536 | /* init read req queue */ | ||
537 | INIT_LIST_HEAD(&priv->read_req_list); | ||
538 | |||
539 | /* process configurable parameters */ | ||
540 | iwmct_dbg_init_params(priv); | ||
541 | ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group); | ||
542 | if (ret) { | ||
543 | LOG_ERROR(priv, INIT, "Failed to register attributes and " | ||
544 | "initialize module_params\n"); | ||
545 | goto error_dev_attrs; | ||
546 | } | ||
547 | |||
548 | iwmct_dbgfs_register(priv, DRV_NAME); | ||
549 | |||
550 | if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) { | ||
551 | LOG_INFO(priv, INIT, | ||
552 | "Reducing transaction to 8 blocks = 2K (from %d)\n", | ||
553 | priv->dbg.download_trans_blks); | ||
554 | priv->dbg.download_trans_blks = 8; | ||
555 | } | ||
556 | priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size; | ||
557 | LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len); | ||
558 | |||
559 | ret = sdio_claim_irq(func, iwmct_irq); | ||
560 | if (ret) { | ||
561 | LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret); | ||
562 | goto error_claim_irq; | ||
563 | } | ||
564 | |||
565 | |||
566 | /* Enable function's interrupt */ | ||
567 | sdio_writeb(priv->func, val, addr, &ret); | ||
568 | if (ret) { | ||
569 | LOG_ERROR(priv, INIT, "Failure writing to " | ||
570 | "Interrupt Enable Register (%d): %d\n", addr, ret); | ||
571 | goto error_enable_int; | ||
572 | } | ||
573 | |||
574 | sdio_release_host(func); | ||
575 | |||
576 | LOG_INFO(priv, INIT, "exit iwmct_probe\n"); | ||
577 | |||
578 | return ret; | ||
579 | |||
580 | error_enable_int: | ||
581 | sdio_release_irq(func); | ||
582 | error_claim_irq: | ||
583 | sdio_disable_func(func); | ||
584 | error_dev_attrs: | ||
585 | iwmct_dbgfs_unregister(priv->dbgfs); | ||
586 | sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); | ||
587 | error_sdio_enable: | ||
588 | sdio_release_host(func); | ||
589 | return ret; | ||
590 | } | ||
591 | |||
592 | static void iwmct_remove(struct sdio_func *func) | ||
593 | { | ||
594 | struct iwmct_work_struct *read_req; | ||
595 | struct iwmct_priv *priv = sdio_get_drvdata(func); | ||
596 | |||
597 | LOG_INFO(priv, INIT, "enter\n"); | ||
598 | |||
599 | sdio_claim_host(func); | ||
600 | sdio_release_irq(func); | ||
601 | sdio_release_host(func); | ||
602 | |||
603 | /* Make sure works are finished */ | ||
604 | flush_work_sync(&priv->bus_rescan_worker); | ||
605 | flush_work_sync(&priv->isr_worker); | ||
606 | |||
607 | sdio_claim_host(func); | ||
608 | sdio_disable_func(func); | ||
609 | sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); | ||
610 | iwmct_dbgfs_unregister(priv->dbgfs); | ||
611 | sdio_release_host(func); | ||
612 | |||
613 | /* free read requests */ | ||
614 | while (!list_empty(&priv->read_req_list)) { | ||
615 | read_req = list_entry(priv->read_req_list.next, | ||
616 | struct iwmct_work_struct, list); | ||
617 | |||
618 | list_del(&read_req->list); | ||
619 | kfree(read_req); | ||
620 | } | ||
621 | |||
622 | kfree(priv); | ||
623 | } | ||
624 | |||
625 | |||
626 | static const struct sdio_device_id iwmct_ids[] = { | ||
627 | /* Intel Wireless MultiCom 3200 Top Driver */ | ||
628 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1404)}, | ||
629 | { }, /* Terminating entry */ | ||
630 | }; | ||
631 | |||
632 | MODULE_DEVICE_TABLE(sdio, iwmct_ids); | ||
633 | |||
634 | static struct sdio_driver iwmct_driver = { | ||
635 | .probe = iwmct_probe, | ||
636 | .remove = iwmct_remove, | ||
637 | .name = DRV_NAME, | ||
638 | .id_table = iwmct_ids, | ||
639 | }; | ||
640 | |||
641 | static int __init iwmct_init(void) | ||
642 | { | ||
643 | int rc; | ||
644 | |||
645 | /* Default log filter settings */ | ||
646 | iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); | ||
647 | iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL); | ||
648 | iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); | ||
649 | |||
650 | rc = sdio_register_driver(&iwmct_driver); | ||
651 | |||
652 | return rc; | ||
653 | } | ||
654 | |||
655 | static void __exit iwmct_exit(void) | ||
656 | { | ||
657 | sdio_unregister_driver(&iwmct_driver); | ||
658 | } | ||
659 | |||
660 | module_init(iwmct_init); | ||
661 | module_exit(iwmct_exit); | ||
662 | |||
diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig index 672de18a776c..71453db14258 100644 --- a/drivers/net/wimax/i2400m/Kconfig +++ b/drivers/net/wimax/i2400m/Kconfig | |||
@@ -7,9 +7,6 @@ config WIMAX_I2400M | |||
7 | comment "Enable USB support to see WiMAX USB drivers" | 7 | comment "Enable USB support to see WiMAX USB drivers" |
8 | depends on USB = n | 8 | depends on USB = n |
9 | 9 | ||
10 | comment "Enable MMC support to see WiMAX SDIO drivers" | ||
11 | depends on MMC = n | ||
12 | |||
13 | config WIMAX_I2400M_USB | 10 | config WIMAX_I2400M_USB |
14 | tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)" | 11 | tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)" |
15 | depends on WIMAX && USB | 12 | depends on WIMAX && USB |
@@ -21,25 +18,6 @@ config WIMAX_I2400M_USB | |||
21 | 18 | ||
22 | If unsure, it is safe to select M (module). | 19 | If unsure, it is safe to select M (module). |
23 | 20 | ||
24 | config WIMAX_I2400M_SDIO | ||
25 | tristate "Intel Wireless WiMAX Connection 2400 over SDIO" | ||
26 | depends on WIMAX && MMC | ||
27 | select WIMAX_I2400M | ||
28 | help | ||
29 | Select if you have a device based on the Intel WiMAX | ||
30 | Connection 2400 over SDIO. | ||
31 | |||
32 | If unsure, it is safe to select M (module). | ||
33 | |||
34 | config WIMAX_IWMC3200_SDIO | ||
35 | bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO (EXPERIMENTAL)" | ||
36 | depends on WIMAX_I2400M_SDIO | ||
37 | depends on EXPERIMENTAL | ||
38 | select IWMC3200TOP | ||
39 | help | ||
40 | Select if you have a device based on the Intel Multicom WiMAX | ||
41 | Connection 3200 over SDIO. | ||
42 | |||
43 | config WIMAX_I2400M_DEBUG_LEVEL | 21 | config WIMAX_I2400M_DEBUG_LEVEL |
44 | int "WiMAX i2400m debug level" | 22 | int "WiMAX i2400m debug level" |
45 | depends on WIMAX_I2400M | 23 | depends on WIMAX_I2400M |
diff --git a/drivers/net/wimax/i2400m/Makefile b/drivers/net/wimax/i2400m/Makefile index 5d9e018d31af..f6d19c348082 100644 --- a/drivers/net/wimax/i2400m/Makefile +++ b/drivers/net/wimax/i2400m/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | 1 | ||
2 | obj-$(CONFIG_WIMAX_I2400M) += i2400m.o | 2 | obj-$(CONFIG_WIMAX_I2400M) += i2400m.o |
3 | obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o | 3 | obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o |
4 | obj-$(CONFIG_WIMAX_I2400M_SDIO) += i2400m-sdio.o | ||
5 | 4 | ||
6 | i2400m-y := \ | 5 | i2400m-y := \ |
7 | control.o \ | 6 | control.o \ |
@@ -21,10 +20,3 @@ i2400m-usb-y := \ | |||
21 | usb-tx.o \ | 20 | usb-tx.o \ |
22 | usb-rx.o \ | 21 | usb-rx.o \ |
23 | usb.o | 22 | usb.o |
24 | |||
25 | |||
26 | i2400m-sdio-y := \ | ||
27 | sdio.o \ | ||
28 | sdio-tx.o \ | ||
29 | sdio-fw.o \ | ||
30 | sdio-rx.o | ||
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 47cae7150bc1..850b8bc38bee 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c | |||
@@ -754,8 +754,7 @@ EXPORT_SYMBOL_GPL(i2400m_error_recovery); | |||
754 | /* | 754 | /* |
755 | * Alloc the command and ack buffers for boot mode | 755 | * Alloc the command and ack buffers for boot mode |
756 | * | 756 | * |
757 | * Get the buffers needed to deal with boot mode messages. These | 757 | * Get the buffers needed to deal with boot mode messages. |
758 | * buffers need to be allocated before the sdio receive irq is setup. | ||
759 | */ | 758 | */ |
760 | static | 759 | static |
761 | int i2400m_bm_buf_alloc(struct i2400m *i2400m) | 760 | int i2400m_bm_buf_alloc(struct i2400m *i2400m) |
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index d09e44970e63..283237f6f074 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c | |||
@@ -51,8 +51,7 @@ | |||
51 | * firmware. Normal hardware takes only signed firmware. | 51 | * firmware. Normal hardware takes only signed firmware. |
52 | * | 52 | * |
53 | * On boot mode, in USB, we write to the device using the bulk out | 53 | * On boot mode, in USB, we write to the device using the bulk out |
54 | * endpoint and read from it in the notification endpoint. In SDIO we | 54 | * endpoint and read from it in the notification endpoint. |
55 | * talk to it via the write address and read from the read address. | ||
56 | * | 55 | * |
57 | * Upon entrance to boot mode, the device sends (preceded with a few | 56 | * Upon entrance to boot mode, the device sends (preceded with a few |
58 | * zero length packets (ZLPs) on the notification endpoint in USB) a | 57 | * zero length packets (ZLPs) on the notification endpoint in USB) a |
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h deleted file mode 100644 index 1d63ffdedfde..000000000000 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ /dev/null | |||
@@ -1,157 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless WiMAX Connection 2400m | ||
3 | * SDIO-specific i2400m driver definitions | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * * Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in | ||
16 | * the documentation and/or other materials provided with the | ||
17 | * distribution. | ||
18 | * * Neither the name of Intel Corporation nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | * | ||
35 | * Intel Corporation <linux-wimax@intel.com> | ||
36 | * Brian Bian <brian.bian@intel.com> | ||
37 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
38 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
39 | * Yanir Lubetkin <yanirx.lubetkin@intel.com> | ||
40 | * - Initial implementation | ||
41 | * | ||
42 | * | ||
43 | * This driver implements the bus-specific part of the i2400m for | ||
44 | * SDIO. Check i2400m.h for a generic driver description. | ||
45 | * | ||
46 | * ARCHITECTURE | ||
47 | * | ||
48 | * This driver sits under the bus-generic i2400m driver, providing the | ||
49 | * connection to the device. | ||
50 | * | ||
51 | * When probed, all the function pointers are setup and then the | ||
52 | * bus-generic code called. The generic driver will then use the | ||
53 | * provided pointers for uploading firmware (i2400ms_bus_bm*() in | ||
54 | * sdio-fw.c) and then setting up the device (i2400ms_dev_*() in | ||
55 | * sdio.c). | ||
56 | * | ||
57 | * Once firmware is uploaded, TX functions (sdio-tx.c) are called when | ||
58 | * data is ready for transmission in the TX fifo; then the SDIO IRQ is | ||
59 | * fired and data is available (sdio-rx.c), it is sent to the generic | ||
60 | * driver for processing with i2400m_rx. | ||
61 | */ | ||
62 | |||
63 | #ifndef __I2400M_SDIO_H__ | ||
64 | #define __I2400M_SDIO_H__ | ||
65 | |||
66 | #include "i2400m.h" | ||
67 | |||
68 | /* Host-Device interface for SDIO */ | ||
69 | enum { | ||
70 | I2400M_SDIO_BOOT_RETRIES = 3, | ||
71 | I2400MS_BLK_SIZE = 256, | ||
72 | I2400MS_PL_SIZE_MAX = 0x3E00, | ||
73 | |||
74 | I2400MS_DATA_ADDR = 0x0, | ||
75 | I2400MS_INTR_STATUS_ADDR = 0x13, | ||
76 | I2400MS_INTR_CLEAR_ADDR = 0x13, | ||
77 | I2400MS_INTR_ENABLE_ADDR = 0x14, | ||
78 | I2400MS_INTR_GET_SIZE_ADDR = 0x2C, | ||
79 | /* The number of ticks to wait for the device to signal that | ||
80 | * it is ready */ | ||
81 | I2400MS_INIT_SLEEP_INTERVAL = 100, | ||
82 | /* How long to wait for the device to settle after reset */ | ||
83 | I2400MS_SETTLE_TIME = 40, | ||
84 | /* The number of msec to wait for IOR after sending IOE */ | ||
85 | IWMC3200_IOR_TIMEOUT = 10, | ||
86 | }; | ||
87 | |||
88 | |||
89 | /** | ||
90 | * struct i2400ms - descriptor for a SDIO connected i2400m | ||
91 | * | ||
92 | * @i2400m: bus-generic i2400m implementation; has to be first (see | ||
93 | * it's documentation in i2400m.h). | ||
94 | * | ||
95 | * @func: pointer to our SDIO function | ||
96 | * | ||
97 | * @tx_worker: workqueue struct used to TX data when the bus-generic | ||
98 | * code signals packets are pending for transmission to the device. | ||
99 | * | ||
100 | * @tx_workqueue: workqeueue used for data TX; we don't use the | ||
101 | * system's workqueue as that might cause deadlocks with code in | ||
102 | * the bus-generic driver. The read/write operation to the queue | ||
103 | * is protected with spinlock (tx_lock in struct i2400m) to avoid | ||
104 | * the queue being destroyed in the middle of a the queue read/write | ||
105 | * operation. | ||
106 | * | ||
107 | * @debugfs_dentry: dentry for the SDIO specific debugfs files | ||
108 | * | ||
109 | * Note this value is set to NULL upon destruction; this is | ||
110 | * because some routinges use it to determine if we are inside the | ||
111 | * probe() path or some other path. When debugfs is disabled, | ||
112 | * creation sets the dentry to '(void*) -ENODEV', which is valid | ||
113 | * for the test. | ||
114 | */ | ||
115 | struct i2400ms { | ||
116 | struct i2400m i2400m; /* FIRST! See doc */ | ||
117 | struct sdio_func *func; | ||
118 | |||
119 | struct work_struct tx_worker; | ||
120 | struct workqueue_struct *tx_workqueue; | ||
121 | char tx_wq_name[32]; | ||
122 | |||
123 | struct dentry *debugfs_dentry; | ||
124 | |||
125 | wait_queue_head_t bm_wfa_wq; | ||
126 | int bm_wait_result; | ||
127 | size_t bm_ack_size; | ||
128 | |||
129 | /* Device is any of the iwmc3200 SKUs */ | ||
130 | unsigned iwmc3200:1; | ||
131 | }; | ||
132 | |||
133 | |||
134 | static inline | ||
135 | void i2400ms_init(struct i2400ms *i2400ms) | ||
136 | { | ||
137 | i2400m_init(&i2400ms->i2400m); | ||
138 | } | ||
139 | |||
140 | |||
141 | extern int i2400ms_rx_setup(struct i2400ms *); | ||
142 | extern void i2400ms_rx_release(struct i2400ms *); | ||
143 | |||
144 | extern int i2400ms_tx_setup(struct i2400ms *); | ||
145 | extern void i2400ms_tx_release(struct i2400ms *); | ||
146 | extern void i2400ms_bus_tx_kick(struct i2400m *); | ||
147 | |||
148 | extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, | ||
149 | const struct i2400m_bootrom_header *, | ||
150 | size_t, int); | ||
151 | extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, | ||
152 | struct i2400m_bootrom_header *, | ||
153 | size_t); | ||
154 | extern void i2400ms_bus_bm_release(struct i2400m *); | ||
155 | extern int i2400ms_bus_bm_setup(struct i2400m *); | ||
156 | |||
157 | #endif /* #ifndef __I2400M_SDIO_H__ */ | ||
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index c806d4550212..79c6505b5c20 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h | |||
@@ -46,7 +46,7 @@ | |||
46 | * - bus generic driver (this part) | 46 | * - bus generic driver (this part) |
47 | * | 47 | * |
48 | * The bus specific driver sets up stuff specific to the bus the | 48 | * The bus specific driver sets up stuff specific to the bus the |
49 | * device is connected to (USB, SDIO, PCI, tam-tam...non-authoritative | 49 | * device is connected to (USB, PCI, tam-tam...non-authoritative |
50 | * nor binding list) which is basically the device-model management | 50 | * nor binding list) which is basically the device-model management |
51 | * (probe/disconnect, etc), moving data from device to kernel and | 51 | * (probe/disconnect, etc), moving data from device to kernel and |
52 | * back, doing the power saving details and reseting the device. | 52 | * back, doing the power saving details and reseting the device. |
@@ -238,14 +238,13 @@ struct i2400m_barker_db; | |||
238 | * amount needed for loading firmware, where us dev_start/stop setup | 238 | * amount needed for loading firmware, where us dev_start/stop setup |
239 | * the rest needed to do full data/control traffic. | 239 | * the rest needed to do full data/control traffic. |
240 | * | 240 | * |
241 | * @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16, | 241 | * @bus_tx_block_size: [fill] USB imposes a 16 block size, but other |
242 | * so we have a tx_blk_size variable that the bus layer sets to | 242 | * busses will differ. So we have a tx_blk_size variable that the |
243 | * tell the engine how much of that we need. | 243 | * bus layer sets to tell the engine how much of that we need. |
244 | * | 244 | * |
245 | * @bus_tx_room_min: [fill] Minimum room required while allocating | 245 | * @bus_tx_room_min: [fill] Minimum room required while allocating |
246 | * TX queue's buffer space for message header. SDIO requires | 246 | * TX queue's buffer space for message header. USB requires |
247 | * 224 bytes and USB 16 bytes. Refer bus specific driver code | 247 | * 16 bytes. Refer to bus specific driver code for details. |
248 | * for details. | ||
249 | * | 248 | * |
250 | * @bus_pl_size_max: [fill] Maximum payload size. | 249 | * @bus_pl_size_max: [fill] Maximum payload size. |
251 | * | 250 | * |
diff --git a/drivers/net/wimax/i2400m/sdio-debug-levels.h b/drivers/net/wimax/i2400m/sdio-debug-levels.h deleted file mode 100644 index c51998741301..000000000000 --- a/drivers/net/wimax/i2400m/sdio-debug-levels.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * debug levels control file for the i2400m module's | ||
3 | */ | ||
4 | #ifndef __debug_levels__h__ | ||
5 | #define __debug_levels__h__ | ||
6 | |||
7 | /* Maximum compile and run time debug level for all submodules */ | ||
8 | #define D_MODULENAME i2400m_sdio | ||
9 | #define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL | ||
10 | |||
11 | #include <linux/wimax/debug.h> | ||
12 | |||
13 | /* List of all the enabled modules */ | ||
14 | enum d_module { | ||
15 | D_SUBMODULE_DECLARE(main), | ||
16 | D_SUBMODULE_DECLARE(tx), | ||
17 | D_SUBMODULE_DECLARE(rx), | ||
18 | D_SUBMODULE_DECLARE(fw) | ||
19 | }; | ||
20 | |||
21 | |||
22 | #endif /* #ifndef __debug_levels__h__ */ | ||
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c deleted file mode 100644 index 8e025418f5be..000000000000 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless WiMAX Connection 2400m | ||
3 | * Firmware uploader's SDIO specifics | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * * Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in | ||
16 | * the documentation and/or other materials provided with the | ||
17 | * distribution. | ||
18 | * * Neither the name of Intel Corporation nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | * | ||
35 | * Intel Corporation <linux-wimax@intel.com> | ||
36 | * Yanir Lubetkin <yanirx.lubetkin@intel.com> | ||
37 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
38 | * - Initial implementation | ||
39 | * | ||
40 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
41 | * - Bus generic/specific split for USB | ||
42 | * | ||
43 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
44 | * - Initial implementation for SDIO | ||
45 | * | ||
46 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
47 | * - SDIO rehash for changes in the bus-driver model | ||
48 | * | ||
49 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
50 | * - Make it IRQ based, not polling | ||
51 | * | ||
52 | * THE PROCEDURE | ||
53 | * | ||
54 | * See fw.c for the generic description of this procedure. | ||
55 | * | ||
56 | * This file implements only the SDIO specifics. It boils down to how | ||
57 | * to send a command and waiting for an acknowledgement from the | ||
58 | * device. | ||
59 | * | ||
60 | * All this code is sequential -- all i2400ms_bus_bm_*() functions are | ||
61 | * executed in the same thread, except i2400ms_bm_irq() [on its own by | ||
62 | * the SDIO driver]. This makes it possible to avoid locking. | ||
63 | * | ||
64 | * COMMAND EXECUTION | ||
65 | * | ||
66 | * The generic firmware upload code will call i2400m_bus_bm_cmd_send() | ||
67 | * to send commands. | ||
68 | * | ||
69 | * The SDIO devices expects things in 256 byte blocks, so it will pad | ||
70 | * it, compute the checksum (if needed) and pass it to SDIO. | ||
71 | * | ||
72 | * ACK RECEPTION | ||
73 | * | ||
74 | * This works in IRQ mode -- the fw loader says when to wait for data | ||
75 | * and for that it calls i2400ms_bus_bm_wait_for_ack(). | ||
76 | * | ||
77 | * This checks if there is any data available (RX size > 0); if not, | ||
78 | * waits for the IRQ handler to notify about it. Once there is data, | ||
79 | * it is read and passed to the caller. Doing it this way we don't | ||
80 | * need much coordination/locking, and it makes it much more difficult | ||
81 | * for an interrupt to be lost and the wait_for_ack() function getting | ||
82 | * stuck even when data is pending. | ||
83 | */ | ||
84 | #include <linux/mmc/sdio_func.h> | ||
85 | #include "i2400m-sdio.h" | ||
86 | |||
87 | |||
88 | #define D_SUBMODULE fw | ||
89 | #include "sdio-debug-levels.h" | ||
90 | |||
91 | |||
92 | /* | ||
93 | * Send a boot-mode command to the SDIO function | ||
94 | * | ||
95 | * We use a bounce buffer (i2400m->bm_cmd_buf) because we need to | ||
96 | * touch the header if the RAW flag is not set. | ||
97 | * | ||
98 | * @flags: pass thru from i2400m_bm_cmd() | ||
99 | * @return: cmd_size if ok, < 0 errno code on error. | ||
100 | * | ||
101 | * Note the command is padded to the SDIO block size for the device. | ||
102 | */ | ||
103 | ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m, | ||
104 | const struct i2400m_bootrom_header *_cmd, | ||
105 | size_t cmd_size, int flags) | ||
106 | { | ||
107 | ssize_t result; | ||
108 | struct device *dev = i2400m_dev(i2400m); | ||
109 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
110 | int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); | ||
111 | struct i2400m_bootrom_header *cmd; | ||
112 | /* SDIO restriction */ | ||
113 | size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE); | ||
114 | |||
115 | d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n", | ||
116 | i2400m, _cmd, cmd_size); | ||
117 | result = -E2BIG; | ||
118 | if (cmd_size > I2400M_BM_CMD_BUF_SIZE) | ||
119 | goto error_too_big; | ||
120 | |||
121 | if (_cmd != i2400m->bm_cmd_buf) | ||
122 | memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); | ||
123 | cmd = i2400m->bm_cmd_buf; | ||
124 | if (cmd_size_a > cmd_size) /* Zero pad space */ | ||
125 | memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); | ||
126 | if ((flags & I2400M_BM_CMD_RAW) == 0) { | ||
127 | if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) | ||
128 | dev_warn(dev, "SW BUG: response_required == 0\n"); | ||
129 | i2400m_bm_cmd_prepare(cmd); | ||
130 | } | ||
131 | d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n", | ||
132 | opcode, cmd_size, cmd_size_a); | ||
133 | d_dump(5, dev, cmd, cmd_size); | ||
134 | |||
135 | sdio_claim_host(i2400ms->func); /* Send & check */ | ||
136 | result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR, | ||
137 | i2400m->bm_cmd_buf, cmd_size_a); | ||
138 | sdio_release_host(i2400ms->func); | ||
139 | if (result < 0) { | ||
140 | dev_err(dev, "BM cmd %d: cannot send: %ld\n", | ||
141 | opcode, (long) result); | ||
142 | goto error_cmd_send; | ||
143 | } | ||
144 | result = cmd_size; | ||
145 | error_cmd_send: | ||
146 | error_too_big: | ||
147 | d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n", | ||
148 | i2400m, _cmd, cmd_size, (int) result); | ||
149 | return result; | ||
150 | } | ||
151 | |||
152 | |||
153 | /* | ||
154 | * Read an ack from the device's boot-mode | ||
155 | * | ||
156 | * @i2400m: | ||
157 | * @_ack: pointer to where to store the read data | ||
158 | * @ack_size: how many bytes we should read | ||
159 | * | ||
160 | * Returns: < 0 errno code on error; otherwise, amount of received bytes. | ||
161 | * | ||
162 | * The ACK for a BM command is always at least sizeof(*ack) bytes, so | ||
163 | * check for that. We don't need to check for device reboots | ||
164 | * | ||
165 | */ | ||
166 | ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, | ||
167 | struct i2400m_bootrom_header *ack, | ||
168 | size_t ack_size) | ||
169 | { | ||
170 | ssize_t result; | ||
171 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
172 | struct sdio_func *func = i2400ms->func; | ||
173 | struct device *dev = &func->dev; | ||
174 | int size; | ||
175 | |||
176 | BUG_ON(sizeof(*ack) > ack_size); | ||
177 | |||
178 | d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", | ||
179 | i2400m, ack, ack_size); | ||
180 | |||
181 | result = wait_event_timeout(i2400ms->bm_wfa_wq, | ||
182 | i2400ms->bm_ack_size != -EINPROGRESS, | ||
183 | 2 * HZ); | ||
184 | if (result == 0) { | ||
185 | result = -ETIMEDOUT; | ||
186 | dev_err(dev, "BM: error waiting for an ack\n"); | ||
187 | goto error_timeout; | ||
188 | } | ||
189 | |||
190 | spin_lock(&i2400m->rx_lock); | ||
191 | result = i2400ms->bm_ack_size; | ||
192 | BUG_ON(result == -EINPROGRESS); | ||
193 | if (result < 0) /* so we exit when rx_release() is called */ | ||
194 | dev_err(dev, "BM: %s failed: %zd\n", __func__, result); | ||
195 | else { | ||
196 | size = min(ack_size, i2400ms->bm_ack_size); | ||
197 | memcpy(ack, i2400m->bm_ack_buf, size); | ||
198 | } | ||
199 | /* | ||
200 | * Remember always to clear the bm_ack_size to -EINPROGRESS | ||
201 | * after the RX data is processed | ||
202 | */ | ||
203 | i2400ms->bm_ack_size = -EINPROGRESS; | ||
204 | spin_unlock(&i2400m->rx_lock); | ||
205 | |||
206 | error_timeout: | ||
207 | d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", | ||
208 | i2400m, ack, ack_size, result); | ||
209 | return result; | ||
210 | } | ||
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c deleted file mode 100644 index fb6396dd115f..000000000000 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ /dev/null | |||
@@ -1,301 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless WiMAX Connection 2400m | ||
3 | * SDIO RX handling | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * * Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in | ||
16 | * the documentation and/or other materials provided with the | ||
17 | * distribution. | ||
18 | * * Neither the name of Intel Corporation nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | * | ||
35 | * Intel Corporation <linux-wimax@intel.com> | ||
36 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
37 | * - Initial implementation | ||
38 | * | ||
39 | * | ||
40 | * This handles the RX path on SDIO. | ||
41 | * | ||
42 | * The SDIO bus driver calls the "irq" routine when data is available. | ||
43 | * This is not a traditional interrupt routine since the SDIO bus | ||
44 | * driver calls us from its irq thread context. Because of this | ||
45 | * sleeping in the SDIO RX IRQ routine is okay. | ||
46 | * | ||
47 | * From there on, we obtain the size of the data that is available, | ||
48 | * allocate an skb, copy it and then pass it to the generic driver's | ||
49 | * RX routine [i2400m_rx()]. | ||
50 | * | ||
51 | * ROADMAP | ||
52 | * | ||
53 | * i2400ms_irq() | ||
54 | * i2400ms_rx() | ||
55 | * __i2400ms_rx_get_size() | ||
56 | * i2400m_is_boot_barker() | ||
57 | * i2400m_rx() | ||
58 | * | ||
59 | * i2400ms_rx_setup() | ||
60 | * | ||
61 | * i2400ms_rx_release() | ||
62 | */ | ||
63 | #include <linux/workqueue.h> | ||
64 | #include <linux/wait.h> | ||
65 | #include <linux/skbuff.h> | ||
66 | #include <linux/mmc/sdio.h> | ||
67 | #include <linux/mmc/sdio_func.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include "i2400m-sdio.h" | ||
70 | |||
71 | #define D_SUBMODULE rx | ||
72 | #include "sdio-debug-levels.h" | ||
73 | |||
74 | static const __le32 i2400m_ACK_BARKER[4] = { | ||
75 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
76 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
77 | __constant_cpu_to_le32(I2400M_ACK_BARKER), | ||
78 | __constant_cpu_to_le32(I2400M_ACK_BARKER) | ||
79 | }; | ||
80 | |||
81 | |||
82 | /* | ||
83 | * Read and return the amount of bytes available for RX | ||
84 | * | ||
85 | * The RX size has to be read like this: byte reads of three | ||
86 | * sequential locations; then glue'em together. | ||
87 | * | ||
88 | * sdio_readl() doesn't work. | ||
89 | */ | ||
90 | static ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms) | ||
91 | { | ||
92 | int ret, cnt, val; | ||
93 | ssize_t rx_size; | ||
94 | unsigned xfer_size_addr; | ||
95 | struct sdio_func *func = i2400ms->func; | ||
96 | struct device *dev = &i2400ms->func->dev; | ||
97 | |||
98 | d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms); | ||
99 | xfer_size_addr = I2400MS_INTR_GET_SIZE_ADDR; | ||
100 | rx_size = 0; | ||
101 | for (cnt = 0; cnt < 3; cnt++) { | ||
102 | val = sdio_readb(func, xfer_size_addr + cnt, &ret); | ||
103 | if (ret < 0) { | ||
104 | dev_err(dev, "RX: Can't read byte %d of RX size from " | ||
105 | "0x%08x: %d\n", cnt, xfer_size_addr + cnt, ret); | ||
106 | rx_size = ret; | ||
107 | goto error_read; | ||
108 | } | ||
109 | rx_size = rx_size << 8 | (val & 0xff); | ||
110 | } | ||
111 | d_printf(6, dev, "RX: rx_size is %ld\n", (long) rx_size); | ||
112 | error_read: | ||
113 | d_fnend(7, dev, "(i2400ms %p) = %ld\n", i2400ms, (long) rx_size); | ||
114 | return rx_size; | ||
115 | } | ||
116 | |||
117 | |||
118 | /* | ||
119 | * Read data from the device (when in normal) | ||
120 | * | ||
121 | * Allocate an SKB of the right size, read the data in and then | ||
122 | * deliver it to the generic layer. | ||
123 | * | ||
124 | * We also check for a reboot barker. That means the device died and | ||
125 | * we have to reboot it. | ||
126 | */ | ||
127 | static | ||
128 | void i2400ms_rx(struct i2400ms *i2400ms) | ||
129 | { | ||
130 | int ret; | ||
131 | struct sdio_func *func = i2400ms->func; | ||
132 | struct device *dev = &func->dev; | ||
133 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
134 | struct sk_buff *skb; | ||
135 | ssize_t rx_size; | ||
136 | |||
137 | d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms); | ||
138 | rx_size = __i2400ms_rx_get_size(i2400ms); | ||
139 | if (rx_size < 0) { | ||
140 | ret = rx_size; | ||
141 | goto error_get_size; | ||
142 | } | ||
143 | /* | ||
144 | * Hardware quirk: make sure to clear the INTR status register | ||
145 | * AFTER getting the data transfer size. | ||
146 | */ | ||
147 | sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); | ||
148 | |||
149 | ret = -ENOMEM; | ||
150 | skb = alloc_skb(rx_size, GFP_ATOMIC); | ||
151 | if (NULL == skb) { | ||
152 | dev_err(dev, "RX: unable to alloc skb\n"); | ||
153 | goto error_alloc_skb; | ||
154 | } | ||
155 | ret = sdio_memcpy_fromio(func, skb->data, | ||
156 | I2400MS_DATA_ADDR, rx_size); | ||
157 | if (ret < 0) { | ||
158 | dev_err(dev, "RX: SDIO data read failed: %d\n", ret); | ||
159 | goto error_memcpy_fromio; | ||
160 | } | ||
161 | |||
162 | rmb(); /* make sure we get boot_mode from dev_reset_handle */ | ||
163 | if (unlikely(i2400m->boot_mode == 1)) { | ||
164 | spin_lock(&i2400m->rx_lock); | ||
165 | i2400ms->bm_ack_size = rx_size; | ||
166 | spin_unlock(&i2400m->rx_lock); | ||
167 | memcpy(i2400m->bm_ack_buf, skb->data, rx_size); | ||
168 | wake_up(&i2400ms->bm_wfa_wq); | ||
169 | d_printf(5, dev, "RX: SDIO boot mode message\n"); | ||
170 | kfree_skb(skb); | ||
171 | goto out; | ||
172 | } | ||
173 | ret = -EIO; | ||
174 | if (unlikely(rx_size < sizeof(__le32))) { | ||
175 | dev_err(dev, "HW BUG? only %zu bytes received\n", rx_size); | ||
176 | goto error_bad_size; | ||
177 | } | ||
178 | if (likely(i2400m_is_d2h_barker(skb->data))) { | ||
179 | skb_put(skb, rx_size); | ||
180 | i2400m_rx(i2400m, skb); | ||
181 | } else if (unlikely(i2400m_is_boot_barker(i2400m, | ||
182 | skb->data, rx_size))) { | ||
183 | ret = i2400m_dev_reset_handle(i2400m, "device rebooted"); | ||
184 | dev_err(dev, "RX: SDIO reboot barker\n"); | ||
185 | kfree_skb(skb); | ||
186 | } else { | ||
187 | i2400m_unknown_barker(i2400m, skb->data, rx_size); | ||
188 | kfree_skb(skb); | ||
189 | } | ||
190 | out: | ||
191 | d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); | ||
192 | return; | ||
193 | |||
194 | error_memcpy_fromio: | ||
195 | kfree_skb(skb); | ||
196 | error_alloc_skb: | ||
197 | error_get_size: | ||
198 | error_bad_size: | ||
199 | d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); | ||
200 | } | ||
201 | |||
202 | |||
203 | /* | ||
204 | * Process an interrupt from the SDIO card | ||
205 | * | ||
206 | * FIXME: need to process other events that are not just ready-to-read | ||
207 | * | ||
208 | * Checks there is data ready and then proceeds to read it. | ||
209 | */ | ||
210 | static | ||
211 | void i2400ms_irq(struct sdio_func *func) | ||
212 | { | ||
213 | int ret; | ||
214 | struct i2400ms *i2400ms = sdio_get_drvdata(func); | ||
215 | struct device *dev = &func->dev; | ||
216 | int val; | ||
217 | |||
218 | d_fnstart(6, dev, "(i2400ms %p)\n", i2400ms); | ||
219 | val = sdio_readb(func, I2400MS_INTR_STATUS_ADDR, &ret); | ||
220 | if (ret < 0) { | ||
221 | dev_err(dev, "RX: Can't read interrupt status: %d\n", ret); | ||
222 | goto error_no_irq; | ||
223 | } | ||
224 | if (!val) { | ||
225 | dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n"); | ||
226 | goto error_no_irq; | ||
227 | } | ||
228 | i2400ms_rx(i2400ms); | ||
229 | error_no_irq: | ||
230 | d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); | ||
231 | } | ||
232 | |||
233 | |||
234 | /* | ||
235 | * Setup SDIO RX | ||
236 | * | ||
237 | * Hooks up the IRQ handler and then enables IRQs. | ||
238 | */ | ||
239 | int i2400ms_rx_setup(struct i2400ms *i2400ms) | ||
240 | { | ||
241 | int result; | ||
242 | struct sdio_func *func = i2400ms->func; | ||
243 | struct device *dev = &func->dev; | ||
244 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
245 | |||
246 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | ||
247 | |||
248 | init_waitqueue_head(&i2400ms->bm_wfa_wq); | ||
249 | spin_lock(&i2400m->rx_lock); | ||
250 | i2400ms->bm_wait_result = -EINPROGRESS; | ||
251 | /* | ||
252 | * Before we are about to enable the RX interrupt, make sure | ||
253 | * bm_ack_size is cleared to -EINPROGRESS which indicates | ||
254 | * no RX interrupt happened yet or the previous interrupt | ||
255 | * has been handled, we are ready to take the new interrupt | ||
256 | */ | ||
257 | i2400ms->bm_ack_size = -EINPROGRESS; | ||
258 | spin_unlock(&i2400m->rx_lock); | ||
259 | |||
260 | sdio_claim_host(func); | ||
261 | result = sdio_claim_irq(func, i2400ms_irq); | ||
262 | if (result < 0) { | ||
263 | dev_err(dev, "Cannot claim IRQ: %d\n", result); | ||
264 | goto error_irq_claim; | ||
265 | } | ||
266 | result = 0; | ||
267 | sdio_writeb(func, 1, I2400MS_INTR_ENABLE_ADDR, &result); | ||
268 | if (result < 0) { | ||
269 | sdio_release_irq(func); | ||
270 | dev_err(dev, "Failed to enable interrupts %d\n", result); | ||
271 | } | ||
272 | error_irq_claim: | ||
273 | sdio_release_host(func); | ||
274 | d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); | ||
275 | return result; | ||
276 | } | ||
277 | |||
278 | |||
279 | /* | ||
280 | * Tear down SDIO RX | ||
281 | * | ||
282 | * Disables IRQs in the device and removes the IRQ handler. | ||
283 | */ | ||
284 | void i2400ms_rx_release(struct i2400ms *i2400ms) | ||
285 | { | ||
286 | int result; | ||
287 | struct sdio_func *func = i2400ms->func; | ||
288 | struct device *dev = &func->dev; | ||
289 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
290 | |||
291 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | ||
292 | spin_lock(&i2400m->rx_lock); | ||
293 | i2400ms->bm_ack_size = -EINTR; | ||
294 | spin_unlock(&i2400m->rx_lock); | ||
295 | wake_up_all(&i2400ms->bm_wfa_wq); | ||
296 | sdio_claim_host(func); | ||
297 | sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); | ||
298 | sdio_release_irq(func); | ||
299 | sdio_release_host(func); | ||
300 | d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); | ||
301 | } | ||
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c deleted file mode 100644 index b53cd1c80e3e..000000000000 --- a/drivers/net/wimax/i2400m/sdio-tx.c +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless WiMAX Connection 2400m | ||
3 | * SDIO TX transaction backends | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * | ||
12 | * * Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer. | ||
14 | * * Redistributions in binary form must reproduce the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer in | ||
16 | * the documentation and/or other materials provided with the | ||
17 | * distribution. | ||
18 | * * Neither the name of Intel Corporation nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | * | ||
35 | * Intel Corporation <linux-wimax@intel.com> | ||
36 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
37 | * - Initial implementation | ||
38 | * | ||
39 | * | ||
40 | * Takes the TX messages in the i2400m's driver TX FIFO and sends them | ||
41 | * to the device until there are no more. | ||
42 | * | ||
43 | * If we fail sending the message, we just drop it. There isn't much | ||
44 | * we can do at this point. Most of the traffic is network, which has | ||
45 | * recovery methods for dropped packets. | ||
46 | * | ||
47 | * The SDIO functions are not atomic, so we can't run from the context | ||
48 | * where i2400m->bus_tx_kick() [i2400ms_bus_tx_kick()] is being called | ||
49 | * (some times atomic). Thus, the actual TX work is deferred to a | ||
50 | * workqueue. | ||
51 | * | ||
52 | * ROADMAP | ||
53 | * | ||
54 | * i2400ms_bus_tx_kick() | ||
55 | * i2400ms_tx_submit() [through workqueue] | ||
56 | * | ||
57 | * i2400m_tx_setup() | ||
58 | * | ||
59 | * i2400m_tx_release() | ||
60 | */ | ||
61 | #include <linux/mmc/sdio_func.h> | ||
62 | #include "i2400m-sdio.h" | ||
63 | |||
64 | #define D_SUBMODULE tx | ||
65 | #include "sdio-debug-levels.h" | ||
66 | |||
67 | |||
68 | /* | ||
69 | * Pull TX transations from the TX FIFO and send them to the device | ||
70 | * until there are no more. | ||
71 | */ | ||
72 | static | ||
73 | void i2400ms_tx_submit(struct work_struct *ws) | ||
74 | { | ||
75 | int result; | ||
76 | struct i2400ms *i2400ms = container_of(ws, struct i2400ms, tx_worker); | ||
77 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
78 | struct sdio_func *func = i2400ms->func; | ||
79 | struct device *dev = &func->dev; | ||
80 | struct i2400m_msg_hdr *tx_msg; | ||
81 | size_t tx_msg_size; | ||
82 | |||
83 | d_fnstart(4, dev, "(i2400ms %p, i2400m %p)\n", i2400ms, i2400ms); | ||
84 | |||
85 | while (NULL != (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) { | ||
86 | d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size); | ||
87 | d_dump(5, dev, tx_msg, tx_msg_size); | ||
88 | |||
89 | sdio_claim_host(func); | ||
90 | result = sdio_memcpy_toio(func, 0, tx_msg, tx_msg_size); | ||
91 | sdio_release_host(func); | ||
92 | |||
93 | i2400m_tx_msg_sent(i2400m); | ||
94 | |||
95 | if (result < 0) { | ||
96 | dev_err(dev, "TX: cannot submit TX; tx_msg @%zu %zu B:" | ||
97 | " %d\n", (void *) tx_msg - i2400m->tx_buf, | ||
98 | tx_msg_size, result); | ||
99 | } | ||
100 | |||
101 | if (result == -ETIMEDOUT) { | ||
102 | i2400m_error_recovery(i2400m); | ||
103 | break; | ||
104 | } | ||
105 | d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size); | ||
106 | } | ||
107 | |||
108 | d_fnend(4, dev, "(i2400ms %p) = void\n", i2400ms); | ||
109 | } | ||
110 | |||
111 | |||
112 | /* | ||
113 | * The generic driver notifies us that there is data ready for TX | ||
114 | * | ||
115 | * Schedule a run of i2400ms_tx_submit() to handle it. | ||
116 | */ | ||
117 | void i2400ms_bus_tx_kick(struct i2400m *i2400m) | ||
118 | { | ||
119 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
120 | struct device *dev = &i2400ms->func->dev; | ||
121 | unsigned long flags; | ||
122 | |||
123 | d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m); | ||
124 | |||
125 | /* schedule tx work, this is because tx may block, therefore | ||
126 | * it has to run in a thread context. | ||
127 | */ | ||
128 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
129 | if (i2400ms->tx_workqueue != NULL) | ||
130 | queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker); | ||
131 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
132 | |||
133 | d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); | ||
134 | } | ||
135 | |||
136 | int i2400ms_tx_setup(struct i2400ms *i2400ms) | ||
137 | { | ||
138 | int result; | ||
139 | struct device *dev = &i2400ms->func->dev; | ||
140 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
141 | struct workqueue_struct *tx_workqueue; | ||
142 | unsigned long flags; | ||
143 | |||
144 | d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); | ||
145 | |||
146 | INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit); | ||
147 | snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name), | ||
148 | "%s-tx", i2400m->wimax_dev.name); | ||
149 | tx_workqueue = | ||
150 | create_singlethread_workqueue(i2400ms->tx_wq_name); | ||
151 | if (tx_workqueue == NULL) { | ||
152 | dev_err(dev, "TX: failed to create workqueue\n"); | ||
153 | result = -ENOMEM; | ||
154 | } else | ||
155 | result = 0; | ||
156 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
157 | i2400ms->tx_workqueue = tx_workqueue; | ||
158 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
159 | d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); | ||
160 | return result; | ||
161 | } | ||
162 | |||
163 | void i2400ms_tx_release(struct i2400ms *i2400ms) | ||
164 | { | ||
165 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
166 | struct workqueue_struct *tx_workqueue; | ||
167 | unsigned long flags; | ||
168 | |||
169 | tx_workqueue = i2400ms->tx_workqueue; | ||
170 | |||
171 | spin_lock_irqsave(&i2400m->tx_lock, flags); | ||
172 | i2400ms->tx_workqueue = NULL; | ||
173 | spin_unlock_irqrestore(&i2400m->tx_lock, flags); | ||
174 | |||
175 | if (tx_workqueue) | ||
176 | destroy_workqueue(tx_workqueue); | ||
177 | } | ||
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c deleted file mode 100644 index 21a9edd6e75d..000000000000 --- a/drivers/net/wimax/i2400m/sdio.c +++ /dev/null | |||
@@ -1,602 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless WiMAX Connection 2400m | ||
3 | * Linux driver model glue for the SDIO device, reset & fw upload | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> | ||
7 | * Dirk Brandewie <dirk.j.brandewie@intel.com> | ||
8 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
9 | * Yanir Lubetkin <yanirx.lubetkin@intel.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License version | ||
13 | * 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
23 | * 02110-1301, USA. | ||
24 | * | ||
25 | * | ||
26 | * See i2400m-sdio.h for a general description of this driver. | ||
27 | * | ||
28 | * This file implements driver model glue, and hook ups for the | ||
29 | * generic driver to implement the bus-specific functions (device | ||
30 | * communication setup/tear down, firmware upload and resetting). | ||
31 | * | ||
32 | * ROADMAP | ||
33 | * | ||
34 | * i2400m_probe() | ||
35 | * alloc_netdev() | ||
36 | * i2400ms_netdev_setup() | ||
37 | * i2400ms_init() | ||
38 | * i2400m_netdev_setup() | ||
39 | * i2400ms_enable_function() | ||
40 | * i2400m_setup() | ||
41 | * | ||
42 | * i2400m_remove() | ||
43 | * i2400m_release() | ||
44 | * free_netdev(net_dev) | ||
45 | * | ||
46 | * i2400ms_bus_reset() Called by i2400m_reset | ||
47 | * __i2400ms_reset() | ||
48 | * __i2400ms_send_barker() | ||
49 | */ | ||
50 | |||
51 | #include <linux/slab.h> | ||
52 | #include <linux/debugfs.h> | ||
53 | #include <linux/mmc/sdio_ids.h> | ||
54 | #include <linux/mmc/sdio.h> | ||
55 | #include <linux/mmc/sdio_func.h> | ||
56 | #include "i2400m-sdio.h" | ||
57 | #include <linux/wimax/i2400m.h> | ||
58 | #include <linux/module.h> | ||
59 | |||
60 | #define D_SUBMODULE main | ||
61 | #include "sdio-debug-levels.h" | ||
62 | |||
63 | /* IOE WiMAX function timeout in seconds */ | ||
64 | static int ioe_timeout = 2; | ||
65 | module_param(ioe_timeout, int, 0); | ||
66 | |||
67 | static char i2400ms_debug_params[128]; | ||
68 | module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params), | ||
69 | 0644); | ||
70 | MODULE_PARM_DESC(debug, | ||
71 | "String of space-separated NAME:VALUE pairs, where NAMEs " | ||
72 | "are the different debug submodules and VALUE are the " | ||
73 | "initial debug value to set."); | ||
74 | |||
75 | /* Our firmware file name list */ | ||
76 | static const char *i2400ms_bus_fw_names[] = { | ||
77 | #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" | ||
78 | I2400MS_FW_FILE_NAME, | ||
79 | NULL | ||
80 | }; | ||
81 | |||
82 | |||
83 | static const struct i2400m_poke_table i2400ms_pokes[] = { | ||
84 | I2400M_FW_POKE(0x6BE260, 0x00000088), | ||
85 | I2400M_FW_POKE(0x080550, 0x00000005), | ||
86 | I2400M_FW_POKE(0xAE0000, 0x00000000), | ||
87 | I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad | ||
88 | * things will happen */ | ||
89 | }; | ||
90 | |||
91 | /* | ||
92 | * Enable the SDIO function | ||
93 | * | ||
94 | * Tries to enable the SDIO function; might fail if it is still not | ||
95 | * ready (in some hardware, the SDIO WiMAX function is only enabled | ||
96 | * when we ask it to explicitly doing). Tries until a timeout is | ||
97 | * reached. | ||
98 | * | ||
99 | * The @maxtries argument indicates how many times (at most) it should | ||
100 | * be tried to enable the function. 0 means forever. This acts along | ||
101 | * with the timeout (ie: it'll stop trying as soon as the maximum | ||
102 | * number of tries is reached _or_ as soon as the timeout is reached). | ||
103 | * | ||
104 | * The reverse of this is...sdio_disable_function() | ||
105 | * | ||
106 | * Returns: 0 if the SDIO function was enabled, < 0 errno code on | ||
107 | * error (-ENODEV when it was unable to enable the function). | ||
108 | */ | ||
109 | static | ||
110 | int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries) | ||
111 | { | ||
112 | struct sdio_func *func = i2400ms->func; | ||
113 | u64 timeout; | ||
114 | int err; | ||
115 | struct device *dev = &func->dev; | ||
116 | unsigned tries = 0; | ||
117 | |||
118 | d_fnstart(3, dev, "(func %p)\n", func); | ||
119 | /* Setup timeout (FIXME: This needs to read the CIS table to | ||
120 | * get a real timeout) and then wait for the device to signal | ||
121 | * it is ready */ | ||
122 | timeout = get_jiffies_64() + ioe_timeout * HZ; | ||
123 | err = -ENODEV; | ||
124 | while (err != 0 && time_before64(get_jiffies_64(), timeout)) { | ||
125 | sdio_claim_host(func); | ||
126 | /* | ||
127 | * There is a sillicon bug on the IWMC3200, where the | ||
128 | * IOE timeout will cause problems on Moorestown | ||
129 | * platforms (system hang). We explicitly overwrite | ||
130 | * func->enable_timeout here to work around the issue. | ||
131 | */ | ||
132 | if (i2400ms->iwmc3200) | ||
133 | func->enable_timeout = IWMC3200_IOR_TIMEOUT; | ||
134 | err = sdio_enable_func(func); | ||
135 | if (0 == err) { | ||
136 | sdio_release_host(func); | ||
137 | d_printf(2, dev, "SDIO function enabled\n"); | ||
138 | goto function_enabled; | ||
139 | } | ||
140 | d_printf(2, dev, "SDIO function failed to enable: %d\n", err); | ||
141 | sdio_release_host(func); | ||
142 | if (maxtries > 0 && ++tries >= maxtries) { | ||
143 | err = -ETIME; | ||
144 | break; | ||
145 | } | ||
146 | msleep(I2400MS_INIT_SLEEP_INTERVAL); | ||
147 | } | ||
148 | /* If timed out, device is not there yet -- get -ENODEV so | ||
149 | * the device driver core will retry later on. */ | ||
150 | if (err == -ETIME) { | ||
151 | dev_err(dev, "Can't enable WiMAX function; " | ||
152 | " has the function been enabled?\n"); | ||
153 | err = -ENODEV; | ||
154 | } | ||
155 | function_enabled: | ||
156 | d_fnend(3, dev, "(func %p) = %d\n", func, err); | ||
157 | return err; | ||
158 | } | ||
159 | |||
160 | |||
161 | /* | ||
162 | * Setup minimal device communication infrastructure needed to at | ||
163 | * least be able to update the firmware. | ||
164 | * | ||
165 | * Note the ugly trick: if we are in the probe path | ||
166 | * (i2400ms->debugfs_dentry == NULL), we only retry function | ||
167 | * enablement one, to avoid racing with the iwmc3200 top controller. | ||
168 | */ | ||
169 | static | ||
170 | int i2400ms_bus_setup(struct i2400m *i2400m) | ||
171 | { | ||
172 | int result; | ||
173 | struct i2400ms *i2400ms = | ||
174 | container_of(i2400m, struct i2400ms, i2400m); | ||
175 | struct device *dev = i2400m_dev(i2400m); | ||
176 | struct sdio_func *func = i2400ms->func; | ||
177 | int retries; | ||
178 | |||
179 | sdio_claim_host(func); | ||
180 | result = sdio_set_block_size(func, I2400MS_BLK_SIZE); | ||
181 | sdio_release_host(func); | ||
182 | if (result < 0) { | ||
183 | dev_err(dev, "Failed to set block size: %d\n", result); | ||
184 | goto error_set_blk_size; | ||
185 | } | ||
186 | |||
187 | if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL) | ||
188 | retries = 1; | ||
189 | else | ||
190 | retries = 0; | ||
191 | result = i2400ms_enable_function(i2400ms, retries); | ||
192 | if (result < 0) { | ||
193 | dev_err(dev, "Cannot enable SDIO function: %d\n", result); | ||
194 | goto error_func_enable; | ||
195 | } | ||
196 | |||
197 | result = i2400ms_tx_setup(i2400ms); | ||
198 | if (result < 0) | ||
199 | goto error_tx_setup; | ||
200 | result = i2400ms_rx_setup(i2400ms); | ||
201 | if (result < 0) | ||
202 | goto error_rx_setup; | ||
203 | return 0; | ||
204 | |||
205 | error_rx_setup: | ||
206 | i2400ms_tx_release(i2400ms); | ||
207 | error_tx_setup: | ||
208 | sdio_claim_host(func); | ||
209 | sdio_disable_func(func); | ||
210 | sdio_release_host(func); | ||
211 | error_func_enable: | ||
212 | error_set_blk_size: | ||
213 | return result; | ||
214 | } | ||
215 | |||
216 | |||
217 | /* | ||
218 | * Tear down minimal device communication infrastructure needed to at | ||
219 | * least be able to update the firmware. | ||
220 | */ | ||
221 | static | ||
222 | void i2400ms_bus_release(struct i2400m *i2400m) | ||
223 | { | ||
224 | struct i2400ms *i2400ms = | ||
225 | container_of(i2400m, struct i2400ms, i2400m); | ||
226 | struct sdio_func *func = i2400ms->func; | ||
227 | |||
228 | i2400ms_rx_release(i2400ms); | ||
229 | i2400ms_tx_release(i2400ms); | ||
230 | sdio_claim_host(func); | ||
231 | sdio_disable_func(func); | ||
232 | sdio_release_host(func); | ||
233 | } | ||
234 | |||
235 | |||
236 | /* | ||
237 | * Setup driver resources needed to communicate with the device | ||
238 | * | ||
239 | * The fw needs some time to settle, and it was just uploaded, | ||
240 | * so give it a break first. I'd prefer to just wait for the device to | ||
241 | * send something, but seems the poking we do to enable SDIO stuff | ||
242 | * interferes with it, so just give it a break before starting... | ||
243 | */ | ||
244 | static | ||
245 | int i2400ms_bus_dev_start(struct i2400m *i2400m) | ||
246 | { | ||
247 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
248 | struct sdio_func *func = i2400ms->func; | ||
249 | struct device *dev = &func->dev; | ||
250 | |||
251 | d_fnstart(3, dev, "(i2400m %p)\n", i2400m); | ||
252 | msleep(200); | ||
253 | d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | |||
258 | /* | ||
259 | * Sends a barker buffer to the device | ||
260 | * | ||
261 | * This helper will allocate a kmalloced buffer and use it to transmit | ||
262 | * (then free it). Reason for this is that the SDIO host controller | ||
263 | * expects alignment (unknown exactly which) which the stack won't | ||
264 | * really provide and certain arches/host-controller combinations | ||
265 | * cannot use stack/vmalloc/text areas for DMA transfers. | ||
266 | */ | ||
267 | static | ||
268 | int __i2400ms_send_barker(struct i2400ms *i2400ms, | ||
269 | const __le32 *barker, size_t barker_size) | ||
270 | { | ||
271 | int ret; | ||
272 | struct sdio_func *func = i2400ms->func; | ||
273 | struct device *dev = &func->dev; | ||
274 | void *buffer; | ||
275 | |||
276 | ret = -ENOMEM; | ||
277 | buffer = kmalloc(I2400MS_BLK_SIZE, GFP_KERNEL); | ||
278 | if (buffer == NULL) | ||
279 | goto error_kzalloc; | ||
280 | |||
281 | memcpy(buffer, barker, barker_size); | ||
282 | sdio_claim_host(func); | ||
283 | ret = sdio_memcpy_toio(func, 0, buffer, I2400MS_BLK_SIZE); | ||
284 | sdio_release_host(func); | ||
285 | |||
286 | if (ret < 0) | ||
287 | d_printf(0, dev, "E: barker error: %d\n", ret); | ||
288 | |||
289 | kfree(buffer); | ||
290 | error_kzalloc: | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | |||
295 | /* | ||
296 | * Reset a device at different levels (warm, cold or bus) | ||
297 | * | ||
298 | * @i2400ms: device descriptor | ||
299 | * @reset_type: soft, warm or bus reset (I2400M_RT_WARM/SOFT/BUS) | ||
300 | * | ||
301 | * FIXME: not tested -- need to confirm expected effects | ||
302 | * | ||
303 | * Warm and cold resets get an SDIO reset if they fail (unimplemented) | ||
304 | * | ||
305 | * Warm reset: | ||
306 | * | ||
307 | * The device will be fully reset internally, but won't be | ||
308 | * disconnected from the bus (so no reenumeration will | ||
309 | * happen). Firmware upload will be necessary. | ||
310 | * | ||
311 | * The device will send a reboot barker that will trigger the driver | ||
312 | * to reinitialize the state via __i2400m_dev_reset_handle. | ||
313 | * | ||
314 | * | ||
315 | * Cold and bus reset: | ||
316 | * | ||
317 | * The device will be fully reset internally, disconnected from the | ||
318 | * bus an a reenumeration will happen. Firmware upload will be | ||
319 | * necessary. Thus, we don't do any locking or struct | ||
320 | * reinitialization, as we are going to be fully disconnected and | ||
321 | * reenumerated. | ||
322 | * | ||
323 | * Note we need to return -ENODEV if a warm reset was requested and we | ||
324 | * had to resort to a bus reset. See i2400m_op_reset(), wimax_reset() | ||
325 | * and wimax_dev->op_reset. | ||
326 | * | ||
327 | * WARNING: no driver state saved/fixed | ||
328 | */ | ||
329 | static | ||
330 | int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) | ||
331 | { | ||
332 | int result = 0; | ||
333 | struct i2400ms *i2400ms = | ||
334 | container_of(i2400m, struct i2400ms, i2400m); | ||
335 | struct device *dev = i2400m_dev(i2400m); | ||
336 | static const __le32 i2400m_WARM_BOOT_BARKER[4] = { | ||
337 | cpu_to_le32(I2400M_WARM_RESET_BARKER), | ||
338 | cpu_to_le32(I2400M_WARM_RESET_BARKER), | ||
339 | cpu_to_le32(I2400M_WARM_RESET_BARKER), | ||
340 | cpu_to_le32(I2400M_WARM_RESET_BARKER), | ||
341 | }; | ||
342 | static const __le32 i2400m_COLD_BOOT_BARKER[4] = { | ||
343 | cpu_to_le32(I2400M_COLD_RESET_BARKER), | ||
344 | cpu_to_le32(I2400M_COLD_RESET_BARKER), | ||
345 | cpu_to_le32(I2400M_COLD_RESET_BARKER), | ||
346 | cpu_to_le32(I2400M_COLD_RESET_BARKER), | ||
347 | }; | ||
348 | |||
349 | if (rt == I2400M_RT_WARM) | ||
350 | result = __i2400ms_send_barker(i2400ms, i2400m_WARM_BOOT_BARKER, | ||
351 | sizeof(i2400m_WARM_BOOT_BARKER)); | ||
352 | else if (rt == I2400M_RT_COLD) | ||
353 | result = __i2400ms_send_barker(i2400ms, i2400m_COLD_BOOT_BARKER, | ||
354 | sizeof(i2400m_COLD_BOOT_BARKER)); | ||
355 | else if (rt == I2400M_RT_BUS) { | ||
356 | do_bus_reset: | ||
357 | |||
358 | i2400ms_bus_release(i2400m); | ||
359 | |||
360 | /* Wait for the device to settle */ | ||
361 | msleep(40); | ||
362 | |||
363 | result = i2400ms_bus_setup(i2400m); | ||
364 | } else | ||
365 | BUG(); | ||
366 | if (result < 0 && rt != I2400M_RT_BUS) { | ||
367 | dev_err(dev, "%s reset failed (%d); trying SDIO reset\n", | ||
368 | rt == I2400M_RT_WARM ? "warm" : "cold", result); | ||
369 | rt = I2400M_RT_BUS; | ||
370 | goto do_bus_reset; | ||
371 | } | ||
372 | return result; | ||
373 | } | ||
374 | |||
375 | |||
376 | static | ||
377 | void i2400ms_netdev_setup(struct net_device *net_dev) | ||
378 | { | ||
379 | struct i2400m *i2400m = net_dev_to_i2400m(net_dev); | ||
380 | struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
381 | i2400ms_init(i2400ms); | ||
382 | i2400m_netdev_setup(net_dev); | ||
383 | } | ||
384 | |||
385 | |||
386 | /* | ||
387 | * Debug levels control; see debug.h | ||
388 | */ | ||
389 | struct d_level D_LEVEL[] = { | ||
390 | D_SUBMODULE_DEFINE(main), | ||
391 | D_SUBMODULE_DEFINE(tx), | ||
392 | D_SUBMODULE_DEFINE(rx), | ||
393 | D_SUBMODULE_DEFINE(fw), | ||
394 | }; | ||
395 | size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); | ||
396 | |||
397 | |||
398 | #define __debugfs_register(prefix, name, parent) \ | ||
399 | do { \ | ||
400 | result = d_level_register_debugfs(prefix, name, parent); \ | ||
401 | if (result < 0) \ | ||
402 | goto error; \ | ||
403 | } while (0) | ||
404 | |||
405 | |||
406 | static | ||
407 | int i2400ms_debugfs_add(struct i2400ms *i2400ms) | ||
408 | { | ||
409 | int result; | ||
410 | struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry; | ||
411 | |||
412 | dentry = debugfs_create_dir("i2400m-sdio", dentry); | ||
413 | result = PTR_ERR(dentry); | ||
414 | if (IS_ERR(dentry)) { | ||
415 | if (result == -ENODEV) | ||
416 | result = 0; /* No debugfs support */ | ||
417 | goto error; | ||
418 | } | ||
419 | i2400ms->debugfs_dentry = dentry; | ||
420 | __debugfs_register("dl_", main, dentry); | ||
421 | __debugfs_register("dl_", tx, dentry); | ||
422 | __debugfs_register("dl_", rx, dentry); | ||
423 | __debugfs_register("dl_", fw, dentry); | ||
424 | |||
425 | return 0; | ||
426 | |||
427 | error: | ||
428 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | ||
429 | i2400ms->debugfs_dentry = NULL; | ||
430 | return result; | ||
431 | } | ||
432 | |||
433 | |||
434 | static struct device_type i2400ms_type = { | ||
435 | .name = "wimax", | ||
436 | }; | ||
437 | |||
438 | /* | ||
439 | * Probe a i2400m interface and register it | ||
440 | * | ||
441 | * @func: SDIO function | ||
442 | * @id: SDIO device ID | ||
443 | * @returns: 0 if ok, < 0 errno code on error. | ||
444 | * | ||
445 | * Alloc a net device, initialize the bus-specific details and then | ||
446 | * calls the bus-generic initialization routine. That will register | ||
447 | * the wimax and netdev devices, upload the firmware [using | ||
448 | * _bus_bm_*()], call _bus_dev_start() to finalize the setup of the | ||
449 | * communication with the device and then will start to talk to it to | ||
450 | * finnish setting it up. | ||
451 | * | ||
452 | * Initialization is tricky; some instances of the hw are packed with | ||
453 | * others in a way that requires a third driver that enables the WiMAX | ||
454 | * function. In those cases, we can't enable the SDIO function and | ||
455 | * we'll return with -ENODEV. When the driver that enables the WiMAX | ||
456 | * function does its thing, it has to do a bus_rescan_devices() on the | ||
457 | * SDIO bus so this driver is called again to enumerate the WiMAX | ||
458 | * function. | ||
459 | */ | ||
460 | static | ||
461 | int i2400ms_probe(struct sdio_func *func, | ||
462 | const struct sdio_device_id *id) | ||
463 | { | ||
464 | int result; | ||
465 | struct net_device *net_dev; | ||
466 | struct device *dev = &func->dev; | ||
467 | struct i2400m *i2400m; | ||
468 | struct i2400ms *i2400ms; | ||
469 | |||
470 | /* Allocate instance [calls i2400m_netdev_setup() on it]. */ | ||
471 | result = -ENOMEM; | ||
472 | net_dev = alloc_netdev(sizeof(*i2400ms), "wmx%d", | ||
473 | i2400ms_netdev_setup); | ||
474 | if (net_dev == NULL) { | ||
475 | dev_err(dev, "no memory for network device instance\n"); | ||
476 | goto error_alloc_netdev; | ||
477 | } | ||
478 | SET_NETDEV_DEV(net_dev, dev); | ||
479 | SET_NETDEV_DEVTYPE(net_dev, &i2400ms_type); | ||
480 | i2400m = net_dev_to_i2400m(net_dev); | ||
481 | i2400ms = container_of(i2400m, struct i2400ms, i2400m); | ||
482 | i2400m->wimax_dev.net_dev = net_dev; | ||
483 | i2400ms->func = func; | ||
484 | sdio_set_drvdata(func, i2400ms); | ||
485 | |||
486 | i2400m->bus_tx_block_size = I2400MS_BLK_SIZE; | ||
487 | /* | ||
488 | * Room required in the TX queue for SDIO message to accommodate | ||
489 | * a smallest payload while allocating header space is 224 bytes, | ||
490 | * which is the smallest message size(the block size 256 bytes) | ||
491 | * minus the smallest message header size(32 bytes). | ||
492 | */ | ||
493 | i2400m->bus_tx_room_min = I2400MS_BLK_SIZE - I2400M_PL_ALIGN * 2; | ||
494 | i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; | ||
495 | i2400m->bus_setup = i2400ms_bus_setup; | ||
496 | i2400m->bus_dev_start = i2400ms_bus_dev_start; | ||
497 | i2400m->bus_dev_stop = NULL; | ||
498 | i2400m->bus_release = i2400ms_bus_release; | ||
499 | i2400m->bus_tx_kick = i2400ms_bus_tx_kick; | ||
500 | i2400m->bus_reset = i2400ms_bus_reset; | ||
501 | /* The iwmc3200-wimax sometimes requires the driver to try | ||
502 | * hard when we paint it into a corner. */ | ||
503 | i2400m->bus_bm_retries = I2400M_SDIO_BOOT_RETRIES; | ||
504 | i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; | ||
505 | i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; | ||
506 | i2400m->bus_fw_names = i2400ms_bus_fw_names; | ||
507 | i2400m->bus_bm_mac_addr_impaired = 1; | ||
508 | i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; | ||
509 | |||
510 | switch (func->device) { | ||
511 | case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX: | ||
512 | case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5: | ||
513 | i2400ms->iwmc3200 = 1; | ||
514 | break; | ||
515 | default: | ||
516 | i2400ms->iwmc3200 = 0; | ||
517 | } | ||
518 | |||
519 | result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); | ||
520 | if (result < 0) { | ||
521 | dev_err(dev, "cannot setup device: %d\n", result); | ||
522 | goto error_setup; | ||
523 | } | ||
524 | |||
525 | result = i2400ms_debugfs_add(i2400ms); | ||
526 | if (result < 0) { | ||
527 | dev_err(dev, "cannot create SDIO debugfs: %d\n", | ||
528 | result); | ||
529 | goto error_debugfs_add; | ||
530 | } | ||
531 | return 0; | ||
532 | |||
533 | error_debugfs_add: | ||
534 | i2400m_release(i2400m); | ||
535 | error_setup: | ||
536 | sdio_set_drvdata(func, NULL); | ||
537 | free_netdev(net_dev); | ||
538 | error_alloc_netdev: | ||
539 | return result; | ||
540 | } | ||
541 | |||
542 | |||
543 | static | ||
544 | void i2400ms_remove(struct sdio_func *func) | ||
545 | { | ||
546 | struct device *dev = &func->dev; | ||
547 | struct i2400ms *i2400ms = sdio_get_drvdata(func); | ||
548 | struct i2400m *i2400m = &i2400ms->i2400m; | ||
549 | struct net_device *net_dev = i2400m->wimax_dev.net_dev; | ||
550 | |||
551 | d_fnstart(3, dev, "SDIO func %p\n", func); | ||
552 | debugfs_remove_recursive(i2400ms->debugfs_dentry); | ||
553 | i2400ms->debugfs_dentry = NULL; | ||
554 | i2400m_release(i2400m); | ||
555 | sdio_set_drvdata(func, NULL); | ||
556 | free_netdev(net_dev); | ||
557 | d_fnend(3, dev, "SDIO func %p\n", func); | ||
558 | } | ||
559 | |||
560 | static | ||
561 | const struct sdio_device_id i2400ms_sdio_ids[] = { | ||
562 | /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ | ||
563 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, | ||
564 | SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, | ||
565 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, | ||
566 | SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5) }, | ||
567 | { /* end: all zeroes */ }, | ||
568 | }; | ||
569 | MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); | ||
570 | |||
571 | |||
572 | static | ||
573 | struct sdio_driver i2400m_sdio_driver = { | ||
574 | .name = KBUILD_MODNAME, | ||
575 | .probe = i2400ms_probe, | ||
576 | .remove = i2400ms_remove, | ||
577 | .id_table = i2400ms_sdio_ids, | ||
578 | }; | ||
579 | |||
580 | |||
581 | static | ||
582 | int __init i2400ms_driver_init(void) | ||
583 | { | ||
584 | d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params, | ||
585 | "i2400m_sdio.debug"); | ||
586 | return sdio_register_driver(&i2400m_sdio_driver); | ||
587 | } | ||
588 | module_init(i2400ms_driver_init); | ||
589 | |||
590 | |||
591 | static | ||
592 | void __exit i2400ms_driver_exit(void) | ||
593 | { | ||
594 | sdio_unregister_driver(&i2400m_sdio_driver); | ||
595 | } | ||
596 | module_exit(i2400ms_driver_exit); | ||
597 | |||
598 | |||
599 | MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); | ||
600 | MODULE_DESCRIPTION("Intel 2400M WiMAX networking for SDIO"); | ||
601 | MODULE_LICENSE("GPL"); | ||
602 | MODULE_FIRMWARE(I2400MS_FW_FILE_NAME); | ||
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5f58fa53238c..6deaae18db57 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -276,7 +276,6 @@ source "drivers/net/wireless/hostap/Kconfig" | |||
276 | source "drivers/net/wireless/ipw2x00/Kconfig" | 276 | source "drivers/net/wireless/ipw2x00/Kconfig" |
277 | source "drivers/net/wireless/iwlwifi/Kconfig" | 277 | source "drivers/net/wireless/iwlwifi/Kconfig" |
278 | source "drivers/net/wireless/iwlegacy/Kconfig" | 278 | source "drivers/net/wireless/iwlegacy/Kconfig" |
279 | source "drivers/net/wireless/iwmc3200wifi/Kconfig" | ||
280 | source "drivers/net/wireless/libertas/Kconfig" | 279 | source "drivers/net/wireless/libertas/Kconfig" |
281 | source "drivers/net/wireless/orinoco/Kconfig" | 280 | source "drivers/net/wireless/orinoco/Kconfig" |
282 | source "drivers/net/wireless/p54/Kconfig" | 281 | source "drivers/net/wireless/p54/Kconfig" |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0ce218b931d4..062dfdff6364 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -53,8 +53,6 @@ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o | |||
53 | 53 | ||
54 | obj-$(CONFIG_WL_TI) += ti/ | 54 | obj-$(CONFIG_WL_TI) += ti/ |
55 | 55 | ||
56 | obj-$(CONFIG_IWM) += iwmc3200wifi/ | ||
57 | |||
58 | obj-$(CONFIG_MWIFIEX) += mwifiex/ | 56 | obj-$(CONFIG_MWIFIEX) += mwifiex/ |
59 | 57 | ||
60 | obj-$(CONFIG_BRCMFMAC) += brcm80211/ | 58 | obj-$(CONFIG_BRCMFMAC) += brcm80211/ |
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index e18a9aa7b6ca..338c5c42357d 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig | |||
@@ -64,3 +64,11 @@ config ATH5K_PCI | |||
64 | ---help--- | 64 | ---help--- |
65 | This adds support for PCI type chipsets of the 5xxx Atheros | 65 | This adds support for PCI type chipsets of the 5xxx Atheros |
66 | family. | 66 | family. |
67 | |||
68 | config ATH5K_TEST_CHANNELS | ||
69 | bool "Enables testing channels on ath5k" | ||
70 | depends on ATH5K && CFG80211_CERTIFICATION_ONUS | ||
71 | ---help--- | ||
72 | This enables non-standard IEEE 802.11 channels on ath5k, which | ||
73 | can be used for research purposes. This option should be disabled | ||
74 | unless doing research. | ||
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 44ad6fe0278f..8c4c040a47b8 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -74,10 +74,6 @@ bool ath5k_modparam_nohwcrypt; | |||
74 | module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); | 74 | module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); |
75 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 75 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
76 | 76 | ||
77 | static bool modparam_all_channels; | ||
78 | module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); | ||
79 | MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); | ||
80 | |||
81 | static bool modparam_fastchanswitch; | 77 | static bool modparam_fastchanswitch; |
82 | module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); | 78 | module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); |
83 | MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); | 79 | MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); |
@@ -258,8 +254,15 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re | |||
258 | \********************/ | 254 | \********************/ |
259 | 255 | ||
260 | /* | 256 | /* |
261 | * Returns true for the channel numbers used without all_channels modparam. | 257 | * Returns true for the channel numbers used. |
262 | */ | 258 | */ |
259 | #ifdef CONFIG_ATH5K_TEST_CHANNELS | ||
260 | static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) | ||
261 | { | ||
262 | return true; | ||
263 | } | ||
264 | |||
265 | #else | ||
263 | static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) | 266 | static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) |
264 | { | 267 | { |
265 | if (band == IEEE80211_BAND_2GHZ && chan <= 14) | 268 | if (band == IEEE80211_BAND_2GHZ && chan <= 14) |
@@ -276,6 +279,7 @@ static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) | |||
276 | /* 802.11j 4.9GHz (20MHz) */ | 279 | /* 802.11j 4.9GHz (20MHz) */ |
277 | (chan == 184 || chan == 188 || chan == 192 || chan == 196)); | 280 | (chan == 184 || chan == 188 || chan == 192 || chan == 196)); |
278 | } | 281 | } |
282 | #endif | ||
279 | 283 | ||
280 | static unsigned int | 284 | static unsigned int |
281 | ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, | 285 | ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, |
@@ -316,8 +320,7 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, | |||
316 | if (!ath5k_channel_ok(ah, &channels[count])) | 320 | if (!ath5k_channel_ok(ah, &channels[count])) |
317 | continue; | 321 | continue; |
318 | 322 | ||
319 | if (!modparam_all_channels && | 323 | if (!ath5k_is_standard_channel(ch, band)) |
320 | !ath5k_is_standard_channel(ch, band)) | ||
321 | continue; | 324 | continue; |
322 | 325 | ||
323 | count++; | 326 | count++; |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fd7dbd4609df..aca1d2689e90 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -3627,6 +3627,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3627 | wiphy->cipher_suites = cipher_suites; | 3627 | wiphy->cipher_suites = cipher_suites; |
3628 | wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | 3628 | wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
3629 | 3629 | ||
3630 | #ifdef CONFIG_PM | ||
3630 | wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 3631 | wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
3631 | WIPHY_WOWLAN_DISCONNECT | | 3632 | WIPHY_WOWLAN_DISCONNECT | |
3632 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | | 3633 | WIPHY_WOWLAN_GTK_REKEY_FAILURE | |
@@ -3636,6 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3636 | wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; | 3637 | wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; |
3637 | wiphy->wowlan.pattern_min_len = 1; | 3638 | wiphy->wowlan.pattern_min_len = 1; |
3638 | wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; | 3639 | wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; |
3640 | #endif | ||
3639 | 3641 | ||
3640 | wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS; | 3642 | wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS; |
3641 | 3643 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 4a4e8a2b9d2c..3a69804f4c16 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c | |||
@@ -35,6 +35,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { | |||
35 | .name = "ar934x_wmac", | 35 | .name = "ar934x_wmac", |
36 | .driver_data = AR9300_DEVID_AR9340, | 36 | .driver_data = AR9300_DEVID_AR9340, |
37 | }, | 37 | }, |
38 | { | ||
39 | .name = "qca955x_wmac", | ||
40 | .driver_data = AR9300_DEVID_QCA955X, | ||
41 | }, | ||
38 | {}, | 42 | {}, |
39 | }; | 43 | }; |
40 | 44 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index d7deb8c9f299..84b558d126ca 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
@@ -159,14 +159,11 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, | |||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | /* Do NF cal only at longer intervals */ | 162 | /* |
163 | if (longcal) { | 163 | * Do NF cal only at longer intervals. Get the value from |
164 | /* | 164 | * the previous NF cal and update history buffer. |
165 | * Get the value from the previous NF cal and update | 165 | */ |
166 | * history buffer. | 166 | if (longcal && ath9k_hw_getnf(ah, chan)) { |
167 | */ | ||
168 | ath9k_hw_getnf(ah, chan); | ||
169 | |||
170 | /* | 167 | /* |
171 | * Load the NF from history buffer of the current channel. | 168 | * Load the NF from history buffer of the current channel. |
172 | * NF is slow time-variant, so it is OK to use a historical | 169 | * NF is slow time-variant, so it is OK to use a historical |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b1e59236d245..ab2bfcb3bed2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
@@ -3509,7 +3509,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) | |||
3509 | 3509 | ||
3510 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) | 3510 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) |
3511 | REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); | 3511 | REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); |
3512 | else if (AR_SREV_9462(ah)) | 3512 | else if (AR_SREV_9462(ah) || AR_SREV_9550(ah)) |
3513 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); | 3513 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); |
3514 | else { | 3514 | else { |
3515 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); | 3515 | REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); |
@@ -3591,6 +3591,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) | |||
3591 | if (AR_SREV_9462(ah)) { | 3591 | if (AR_SREV_9462(ah)) { |
3592 | REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, | 3592 | REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, |
3593 | AR_SWITCH_TABLE_COM_AR9462_ALL, value); | 3593 | AR_SWITCH_TABLE_COM_AR9462_ALL, value); |
3594 | } else if (AR_SREV_9550(ah)) { | ||
3595 | REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, | ||
3596 | AR_SWITCH_TABLE_COM_AR9550_ALL, value); | ||
3594 | } else | 3597 | } else |
3595 | REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, | 3598 | REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, |
3596 | AR_SWITCH_TABLE_COM_ALL, value); | 3599 | AR_SWITCH_TABLE_COM_ALL, value); |
@@ -3957,7 +3960,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, | |||
3957 | ar9003_hw_drive_strength_apply(ah); | 3960 | ar9003_hw_drive_strength_apply(ah); |
3958 | ar9003_hw_atten_apply(ah, chan); | 3961 | ar9003_hw_atten_apply(ah, chan); |
3959 | ar9003_hw_quick_drop_apply(ah, chan->channel); | 3962 | ar9003_hw_quick_drop_apply(ah, chan->channel); |
3960 | if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah)) | 3963 | if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) |
3961 | ar9003_hw_internal_regulator_apply(ah); | 3964 | ar9003_hw_internal_regulator_apply(ah); |
3962 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) | 3965 | if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) |
3963 | ar9003_hw_apply_tuning_caps(ah); | 3966 | ar9003_hw_apply_tuning_caps(ah); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index a0e3394b10dc..41e88c660e48 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "ar9340_initvals.h" | 21 | #include "ar9340_initvals.h" |
22 | #include "ar9330_1p1_initvals.h" | 22 | #include "ar9330_1p1_initvals.h" |
23 | #include "ar9330_1p2_initvals.h" | 23 | #include "ar9330_1p2_initvals.h" |
24 | #include "ar955x_1p0_initvals.h" | ||
24 | #include "ar9580_1p0_initvals.h" | 25 | #include "ar9580_1p0_initvals.h" |
25 | #include "ar9462_2p0_initvals.h" | 26 | #include "ar9462_2p0_initvals.h" |
26 | 27 | ||
@@ -327,7 +328,61 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) | |||
327 | 328 | ||
328 | INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ, | 329 | INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ, |
329 | ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2); | 330 | ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2); |
331 | } else if (AR_SREV_9550(ah)) { | ||
332 | /* mac */ | ||
333 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); | ||
334 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], | ||
335 | ar955x_1p0_mac_core, | ||
336 | ARRAY_SIZE(ar955x_1p0_mac_core), 2); | ||
337 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], | ||
338 | ar955x_1p0_mac_postamble, | ||
339 | ARRAY_SIZE(ar955x_1p0_mac_postamble), 5); | ||
340 | |||
341 | /* bb */ | ||
342 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); | ||
343 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], | ||
344 | ar955x_1p0_baseband_core, | ||
345 | ARRAY_SIZE(ar955x_1p0_baseband_core), 2); | ||
346 | INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], | ||
347 | ar955x_1p0_baseband_postamble, | ||
348 | ARRAY_SIZE(ar955x_1p0_baseband_postamble), 5); | ||
349 | |||
350 | /* radio */ | ||
351 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); | ||
352 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], | ||
353 | ar955x_1p0_radio_core, | ||
354 | ARRAY_SIZE(ar955x_1p0_radio_core), 2); | ||
355 | INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], | ||
356 | ar955x_1p0_radio_postamble, | ||
357 | ARRAY_SIZE(ar955x_1p0_radio_postamble), 5); | ||
358 | |||
359 | /* soc */ | ||
360 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], | ||
361 | ar955x_1p0_soc_preamble, | ||
362 | ARRAY_SIZE(ar955x_1p0_soc_preamble), 2); | ||
363 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); | ||
364 | INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], | ||
365 | ar955x_1p0_soc_postamble, | ||
366 | ARRAY_SIZE(ar955x_1p0_soc_postamble), 5); | ||
330 | 367 | ||
368 | /* rx/tx gain */ | ||
369 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
370 | ar955x_1p0_common_wo_xlna_rx_gain_table, | ||
371 | ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), | ||
372 | 2); | ||
373 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | ||
374 | ar955x_1p0_common_wo_xlna_rx_gain_bounds, | ||
375 | ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), | ||
376 | 5); | ||
377 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
378 | ar955x_1p0_modes_xpa_tx_gain_table, | ||
379 | ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), | ||
380 | 9); | ||
381 | |||
382 | /* Fast clock modal settings */ | ||
383 | INIT_INI_ARRAY(&ah->iniModesFastClock, | ||
384 | ar955x_1p0_modes_fast_clock, | ||
385 | ARRAY_SIZE(ar955x_1p0_modes_fast_clock), 3); | ||
331 | } else if (AR_SREV_9580(ah)) { | 386 | } else if (AR_SREV_9580(ah)) { |
332 | /* mac */ | 387 | /* mac */ |
333 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); | 388 | INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); |
@@ -470,6 +525,11 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) | |||
470 | ar9485_modes_lowest_ob_db_tx_gain_1_1, | 525 | ar9485_modes_lowest_ob_db_tx_gain_1_1, |
471 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), | 526 | ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), |
472 | 5); | 527 | 5); |
528 | else if (AR_SREV_9550(ah)) | ||
529 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
530 | ar955x_1p0_modes_xpa_tx_gain_table, | ||
531 | ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), | ||
532 | 9); | ||
473 | else if (AR_SREV_9580(ah)) | 533 | else if (AR_SREV_9580(ah)) |
474 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 534 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
475 | ar9580_1p0_lowest_ob_db_tx_gain_table, | 535 | ar9580_1p0_lowest_ob_db_tx_gain_table, |
@@ -514,6 +574,11 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) | |||
514 | ar9580_1p0_high_ob_db_tx_gain_table, | 574 | ar9580_1p0_high_ob_db_tx_gain_table, |
515 | ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), | 575 | ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), |
516 | 5); | 576 | 5); |
577 | else if (AR_SREV_9550(ah)) | ||
578 | INIT_INI_ARRAY(&ah->iniModesTxGain, | ||
579 | ar955x_1p0_modes_no_xpa_tx_gain_table, | ||
580 | ARRAY_SIZE(ar955x_1p0_modes_no_xpa_tx_gain_table), | ||
581 | 9); | ||
517 | else if (AR_SREV_9462_20(ah)) | 582 | else if (AR_SREV_9462_20(ah)) |
518 | INIT_INI_ARRAY(&ah->iniModesTxGain, | 583 | INIT_INI_ARRAY(&ah->iniModesTxGain, |
519 | ar9462_modes_high_ob_db_tx_gain_table_2p0, | 584 | ar9462_modes_high_ob_db_tx_gain_table_2p0, |
@@ -635,7 +700,16 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) | |||
635 | ar9485Common_wo_xlna_rx_gain_1_1, | 700 | ar9485Common_wo_xlna_rx_gain_1_1, |
636 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), | 701 | ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), |
637 | 2); | 702 | 2); |
638 | else if (AR_SREV_9580(ah)) | 703 | else if (AR_SREV_9550(ah)) { |
704 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
705 | ar955x_1p0_common_rx_gain_table, | ||
706 | ARRAY_SIZE(ar955x_1p0_common_rx_gain_table), | ||
707 | 2); | ||
708 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | ||
709 | ar955x_1p0_common_rx_gain_bounds, | ||
710 | ARRAY_SIZE(ar955x_1p0_common_rx_gain_bounds), | ||
711 | 5); | ||
712 | } else if (AR_SREV_9580(ah)) | ||
639 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 713 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
640 | ar9580_1p0_rx_gain_table, | 714 | ar9580_1p0_rx_gain_table, |
641 | ARRAY_SIZE(ar9580_1p0_rx_gain_table), | 715 | ARRAY_SIZE(ar9580_1p0_rx_gain_table), |
@@ -679,7 +753,16 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) | |||
679 | ar9462_common_wo_xlna_rx_gain_table_2p0, | 753 | ar9462_common_wo_xlna_rx_gain_table_2p0, |
680 | ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0), | 754 | ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0), |
681 | 2); | 755 | 2); |
682 | else if (AR_SREV_9580(ah)) | 756 | else if (AR_SREV_9550(ah)) { |
757 | INIT_INI_ARRAY(&ah->iniModesRxGain, | ||
758 | ar955x_1p0_common_wo_xlna_rx_gain_table, | ||
759 | ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), | ||
760 | 2); | ||
761 | INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, | ||
762 | ar955x_1p0_common_wo_xlna_rx_gain_bounds, | ||
763 | ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), | ||
764 | 5); | ||
765 | } else if (AR_SREV_9580(ah)) | ||
683 | INIT_INI_ARRAY(&ah->iniModesRxGain, | 766 | INIT_INI_ARRAY(&ah->iniModesRxGain, |
684 | ar9580_1p0_wo_xlna_rx_gain_table, | 767 | ar9580_1p0_wo_xlna_rx_gain_table, |
685 | ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table), | 768 | ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table), |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 61558375bfbf..9a34fcaae3ff 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c | |||
@@ -1015,12 +1015,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) | |||
1015 | return; | 1015 | return; |
1016 | 1016 | ||
1017 | if (mci->is_2g) { | 1017 | if (mci->is_2g) { |
1018 | if (!force) { | 1018 | ar9003_mci_send_2g5g_status(ah, true); |
1019 | ar9003_mci_send_2g5g_status(ah, true); | 1019 | ar9003_mci_send_lna_transfer(ah, true); |
1020 | 1020 | udelay(5); | |
1021 | ar9003_mci_send_lna_transfer(ah, true); | ||
1022 | udelay(5); | ||
1023 | } | ||
1024 | 1021 | ||
1025 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, | 1022 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, |
1026 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | 1023 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
@@ -1030,10 +1027,8 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) | |||
1030 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) | 1027 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) |
1031 | ar9003_mci_osla_setup(ah, true); | 1028 | ar9003_mci_osla_setup(ah, true); |
1032 | } else { | 1029 | } else { |
1033 | if (!force) { | 1030 | ar9003_mci_send_lna_take(ah, true); |
1034 | ar9003_mci_send_lna_take(ah, true); | 1031 | udelay(5); |
1035 | udelay(5); | ||
1036 | } | ||
1037 | 1032 | ||
1038 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, | 1033 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, |
1039 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | 1034 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
@@ -1041,8 +1036,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) | |||
1041 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); | 1036 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); |
1042 | 1037 | ||
1043 | ar9003_mci_osla_setup(ah, false); | 1038 | ar9003_mci_osla_setup(ah, false); |
1044 | if (!force) | 1039 | ar9003_mci_send_2g5g_status(ah, true); |
1045 | ar9003_mci_send_2g5g_status(ah, true); | ||
1046 | } | 1040 | } |
1047 | } | 1041 | } |
1048 | 1042 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 3d400e8d6535..2c9f7d7ed4cc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c | |||
@@ -211,7 +211,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) | |||
211 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); | 211 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); |
212 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, | 212 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, |
213 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); | 213 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); |
214 | if (AR_SREV_9485(ah) || AR_SREV_9462(ah)) | 214 | if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9550(ah)) |
215 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, | 215 | REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, |
216 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, | 216 | AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, |
217 | -3); | 217 | -3); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 6b91ebb158fe..d2346dbad6cd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -99,7 +99,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) | |||
99 | channelSel = (freq * 4) / 120; | 99 | channelSel = (freq * 4) / 120; |
100 | chan_frac = (((freq * 4) % 120) * 0x20000) / 120; | 100 | chan_frac = (((freq * 4) % 120) * 0x20000) / 120; |
101 | channelSel = (channelSel << 17) | chan_frac; | 101 | channelSel = (channelSel << 17) | chan_frac; |
102 | } else if (AR_SREV_9340(ah)) { | 102 | } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { |
103 | if (ah->is_clk_25mhz) { | 103 | if (ah->is_clk_25mhz) { |
104 | u32 chan_frac; | 104 | u32 chan_frac; |
105 | 105 | ||
@@ -113,7 +113,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) | |||
113 | /* Set to 2G mode */ | 113 | /* Set to 2G mode */ |
114 | bMode = 1; | 114 | bMode = 1; |
115 | } else { | 115 | } else { |
116 | if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { | 116 | if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && |
117 | ah->is_clk_25mhz) { | ||
117 | u32 chan_frac; | 118 | u32 chan_frac; |
118 | 119 | ||
119 | channelSel = (freq * 2) / 75; | 120 | channelSel = (freq * 2) / 75; |
@@ -180,7 +181,8 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, | |||
180 | * is out-of-band and can be ignored. | 181 | * is out-of-band and can be ignored. |
181 | */ | 182 | */ |
182 | 183 | ||
183 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) { | 184 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || |
185 | AR_SREV_9550(ah)) { | ||
184 | if (spur_fbin_ptr[0] == 0) /* No spur */ | 186 | if (spur_fbin_ptr[0] == 0) /* No spur */ |
185 | return; | 187 | return; |
186 | max_spur_cnts = 5; | 188 | max_spur_cnts = 5; |
@@ -205,7 +207,8 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, | |||
205 | if (AR_SREV_9462(ah) && (i == 0 || i == 3)) | 207 | if (AR_SREV_9462(ah) && (i == 0 || i == 3)) |
206 | continue; | 208 | continue; |
207 | negative = 0; | 209 | negative = 0; |
208 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) | 210 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || |
211 | AR_SREV_9550(ah)) | ||
209 | cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], | 212 | cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], |
210 | IS_CHAN_2GHZ(chan)); | 213 | IS_CHAN_2GHZ(chan)); |
211 | else | 214 | else |
@@ -618,6 +621,50 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah, | |||
618 | } | 621 | } |
619 | } | 622 | } |
620 | 623 | ||
624 | static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, | ||
625 | struct ath9k_channel *chan) | ||
626 | { | ||
627 | int ret; | ||
628 | |||
629 | switch (chan->chanmode) { | ||
630 | case CHANNEL_A: | ||
631 | case CHANNEL_A_HT20: | ||
632 | if (chan->channel <= 5350) | ||
633 | ret = 1; | ||
634 | else if ((chan->channel > 5350) && (chan->channel <= 5600)) | ||
635 | ret = 3; | ||
636 | else | ||
637 | ret = 5; | ||
638 | break; | ||
639 | |||
640 | case CHANNEL_A_HT40PLUS: | ||
641 | case CHANNEL_A_HT40MINUS: | ||
642 | if (chan->channel <= 5350) | ||
643 | ret = 2; | ||
644 | else if ((chan->channel > 5350) && (chan->channel <= 5600)) | ||
645 | ret = 4; | ||
646 | else | ||
647 | ret = 6; | ||
648 | break; | ||
649 | |||
650 | case CHANNEL_G: | ||
651 | case CHANNEL_G_HT20: | ||
652 | case CHANNEL_B: | ||
653 | ret = 8; | ||
654 | break; | ||
655 | |||
656 | case CHANNEL_G_HT40PLUS: | ||
657 | case CHANNEL_G_HT40MINUS: | ||
658 | ret = 7; | ||
659 | break; | ||
660 | |||
661 | default: | ||
662 | ret = -EINVAL; | ||
663 | } | ||
664 | |||
665 | return ret; | ||
666 | } | ||
667 | |||
621 | static int ar9003_hw_process_ini(struct ath_hw *ah, | 668 | static int ar9003_hw_process_ini(struct ath_hw *ah, |
622 | struct ath9k_channel *chan) | 669 | struct ath9k_channel *chan) |
623 | { | 670 | { |
@@ -659,7 +706,22 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, | |||
659 | } | 706 | } |
660 | 707 | ||
661 | REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites); | 708 | REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites); |
662 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); | 709 | if (AR_SREV_9550(ah)) |
710 | REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex, | ||
711 | regWrites); | ||
712 | |||
713 | if (AR_SREV_9550(ah)) { | ||
714 | int modes_txgain_index; | ||
715 | |||
716 | modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); | ||
717 | if (modes_txgain_index < 0) | ||
718 | return -EINVAL; | ||
719 | |||
720 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modes_txgain_index, | ||
721 | regWrites); | ||
722 | } else { | ||
723 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); | ||
724 | } | ||
663 | 725 | ||
664 | /* | 726 | /* |
665 | * For 5GHz channels requiring Fast Clock, apply | 727 | * For 5GHz channels requiring Fast Clock, apply |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index ed662c3bae5b..751c83b21493 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h | |||
@@ -636,8 +636,8 @@ | |||
636 | 636 | ||
637 | #define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ | 637 | #define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ |
638 | ((AR_SREV_9462(ah) ? 0x1628c : 0x16280))) | 638 | ((AR_SREV_9462(ah) ? 0x1628c : 0x16280))) |
639 | #define AR_CH0_TOP_XPABIASLVL (0x300) | 639 | #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) |
640 | #define AR_CH0_TOP_XPABIASLVL_S (8) | 640 | #define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) |
641 | 641 | ||
642 | #define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ | 642 | #define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ |
643 | ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) | 643 | ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) |
@@ -650,6 +650,8 @@ | |||
650 | #define AR_SWITCH_TABLE_COM_ALL_S (0) | 650 | #define AR_SWITCH_TABLE_COM_ALL_S (0) |
651 | #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) | 651 | #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) |
652 | #define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0) | 652 | #define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0) |
653 | #define AR_SWITCH_TABLE_COM_AR9550_ALL (0xffffff) | ||
654 | #define AR_SWITCH_TABLE_COM_AR9550_ALL_S (0) | ||
653 | #define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) | 655 | #define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) |
654 | #define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) | 656 | #define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) |
655 | #define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) | 657 | #define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) |
diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h new file mode 100644 index 000000000000..df97f21c52dc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h | |||
@@ -0,0 +1,1284 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010-2011 Atheros Communications Inc. | ||
3 | * Copyright (c) 2011-2012 Qualcomm Atheros Inc. | ||
4 | * | ||
5 | * Permission to use, copy, modify, and/or distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #ifndef INITVALS_955X_1P0_H | ||
19 | #define INITVALS_955X_1P0_H | ||
20 | |||
21 | /* AR955X 1.0 */ | ||
22 | |||
23 | static const u32 ar955x_1p0_radio_postamble[][5] = { | ||
24 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
25 | {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, | ||
26 | {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a}, | ||
27 | {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800}, | ||
28 | {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a}, | ||
29 | {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | ||
30 | {0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, | ||
31 | {0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, | ||
32 | {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | ||
33 | {0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, | ||
34 | {0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, | ||
35 | {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, | ||
36 | {0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, | ||
37 | {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, | ||
38 | }; | ||
39 | |||
40 | static const u32 ar955x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { | ||
41 | /* Addr allmodes */ | ||
42 | {0x0000a398, 0x00000000}, | ||
43 | {0x0000a39c, 0x6f7f0301}, | ||
44 | {0x0000a3a0, 0xca9228ee}, | ||
45 | }; | ||
46 | |||
47 | static const u32 ar955x_1p0_baseband_postamble[][5] = { | ||
48 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
49 | {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, | ||
50 | {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, | ||
51 | {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, | ||
52 | {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, | ||
53 | {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, | ||
54 | {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, | ||
55 | {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, | ||
56 | {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, | ||
57 | {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, | ||
58 | {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, | ||
59 | {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, | ||
60 | {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, | ||
61 | {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
62 | {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, | ||
63 | {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, | ||
64 | {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, | ||
65 | {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, | ||
66 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
67 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | ||
68 | {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, | ||
69 | {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, | ||
70 | {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, | ||
71 | {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, | ||
72 | {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, | ||
73 | {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, | ||
74 | {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, | ||
75 | {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, | ||
76 | {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, | ||
77 | {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, | ||
78 | {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, | ||
79 | {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, | ||
80 | {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, | ||
81 | {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, | ||
82 | {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | ||
83 | {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, | ||
84 | {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, | ||
85 | {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, | ||
86 | {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, | ||
87 | {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, | ||
88 | {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, | ||
89 | {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
90 | {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
91 | {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, | ||
92 | {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
93 | {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
94 | {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, | ||
95 | {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | ||
96 | {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
97 | {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, | ||
98 | {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
99 | {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, | ||
100 | {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, | ||
101 | {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, | ||
102 | }; | ||
103 | |||
104 | static const u32 ar955x_1p0_radio_core[][2] = { | ||
105 | /* Addr allmodes */ | ||
106 | {0x00016000, 0x36db6db6}, | ||
107 | {0x00016004, 0x6db6db40}, | ||
108 | {0x00016008, 0x73f00000}, | ||
109 | {0x0001600c, 0x00000000}, | ||
110 | {0x00016040, 0x7f80fff8}, | ||
111 | {0x0001604c, 0x76d005b5}, | ||
112 | {0x00016050, 0x557cf031}, | ||
113 | {0x00016054, 0x13449440}, | ||
114 | {0x00016058, 0x0c51c92c}, | ||
115 | {0x0001605c, 0x3db7fffc}, | ||
116 | {0x00016060, 0xfffffffc}, | ||
117 | {0x00016064, 0x000f0278}, | ||
118 | {0x00016068, 0x6db6db6c}, | ||
119 | {0x0001606c, 0x6db60000}, | ||
120 | {0x00016080, 0x00080000}, | ||
121 | {0x00016084, 0x0e48048c}, | ||
122 | {0x00016088, 0x14214514}, | ||
123 | {0x0001608c, 0x119f101e}, | ||
124 | {0x00016090, 0x24926490}, | ||
125 | {0x00016094, 0x00000000}, | ||
126 | {0x000160a0, 0x0a108ffe}, | ||
127 | {0x000160a4, 0x812fc370}, | ||
128 | {0x000160a8, 0x423c8000}, | ||
129 | {0x000160b4, 0x92480080}, | ||
130 | {0x000160c0, 0x006db6d0}, | ||
131 | {0x000160c4, 0x6db6db60}, | ||
132 | {0x000160c8, 0x6db6db6c}, | ||
133 | {0x000160cc, 0x01e6c000}, | ||
134 | {0x00016100, 0x11999601}, | ||
135 | {0x00016108, 0x00080010}, | ||
136 | {0x00016144, 0x02084080}, | ||
137 | {0x00016148, 0x000080c0}, | ||
138 | {0x00016280, 0x01800804}, | ||
139 | {0x00016284, 0x00038dc5}, | ||
140 | {0x00016288, 0x00000000}, | ||
141 | {0x0001628c, 0x00000040}, | ||
142 | {0x00016380, 0x00000000}, | ||
143 | {0x00016384, 0x00000000}, | ||
144 | {0x00016388, 0x00400705}, | ||
145 | {0x0001638c, 0x00800700}, | ||
146 | {0x00016390, 0x00800700}, | ||
147 | {0x00016394, 0x00000000}, | ||
148 | {0x00016398, 0x00000000}, | ||
149 | {0x0001639c, 0x00000000}, | ||
150 | {0x000163a0, 0x00000001}, | ||
151 | {0x000163a4, 0x00000001}, | ||
152 | {0x000163a8, 0x00000000}, | ||
153 | {0x000163ac, 0x00000000}, | ||
154 | {0x000163b0, 0x00000000}, | ||
155 | {0x000163b4, 0x00000000}, | ||
156 | {0x000163b8, 0x00000000}, | ||
157 | {0x000163bc, 0x00000000}, | ||
158 | {0x000163c0, 0x000000a0}, | ||
159 | {0x000163c4, 0x000c0000}, | ||
160 | {0x000163c8, 0x14021402}, | ||
161 | {0x000163cc, 0x00001402}, | ||
162 | {0x000163d0, 0x00000000}, | ||
163 | {0x000163d4, 0x00000000}, | ||
164 | {0x00016400, 0x36db6db6}, | ||
165 | {0x00016404, 0x6db6db40}, | ||
166 | {0x00016408, 0x73f00000}, | ||
167 | {0x0001640c, 0x00000000}, | ||
168 | {0x00016440, 0x7f80fff8}, | ||
169 | {0x0001644c, 0x76d005b5}, | ||
170 | {0x00016450, 0x557cf031}, | ||
171 | {0x00016454, 0x13449440}, | ||
172 | {0x00016458, 0x0c51c92c}, | ||
173 | {0x0001645c, 0x3db7fffc}, | ||
174 | {0x00016460, 0xfffffffc}, | ||
175 | {0x00016464, 0x000f0278}, | ||
176 | {0x00016468, 0x6db6db6c}, | ||
177 | {0x0001646c, 0x6db60000}, | ||
178 | {0x00016500, 0x11999601}, | ||
179 | {0x00016508, 0x00080010}, | ||
180 | {0x00016544, 0x02084080}, | ||
181 | {0x00016548, 0x000080c0}, | ||
182 | {0x00016780, 0x00000000}, | ||
183 | {0x00016784, 0x00000000}, | ||
184 | {0x00016788, 0x00400705}, | ||
185 | {0x0001678c, 0x00800700}, | ||
186 | {0x00016790, 0x00800700}, | ||
187 | {0x00016794, 0x00000000}, | ||
188 | {0x00016798, 0x00000000}, | ||
189 | {0x0001679c, 0x00000000}, | ||
190 | {0x000167a0, 0x00000001}, | ||
191 | {0x000167a4, 0x00000001}, | ||
192 | {0x000167a8, 0x00000000}, | ||
193 | {0x000167ac, 0x00000000}, | ||
194 | {0x000167b0, 0x00000000}, | ||
195 | {0x000167b4, 0x00000000}, | ||
196 | {0x000167b8, 0x00000000}, | ||
197 | {0x000167bc, 0x00000000}, | ||
198 | {0x000167c0, 0x000000a0}, | ||
199 | {0x000167c4, 0x000c0000}, | ||
200 | {0x000167c8, 0x14021402}, | ||
201 | {0x000167cc, 0x00001402}, | ||
202 | {0x000167d0, 0x00000000}, | ||
203 | {0x000167d4, 0x00000000}, | ||
204 | {0x00016800, 0x36db6db6}, | ||
205 | {0x00016804, 0x6db6db40}, | ||
206 | {0x00016808, 0x73f00000}, | ||
207 | {0x0001680c, 0x00000000}, | ||
208 | {0x00016840, 0x7f80fff8}, | ||
209 | {0x0001684c, 0x76d005b5}, | ||
210 | {0x00016850, 0x557cf031}, | ||
211 | {0x00016854, 0x13449440}, | ||
212 | {0x00016858, 0x0c51c92c}, | ||
213 | {0x0001685c, 0x3db7fffc}, | ||
214 | {0x00016860, 0xfffffffc}, | ||
215 | {0x00016864, 0x000f0278}, | ||
216 | {0x00016868, 0x6db6db6c}, | ||
217 | {0x0001686c, 0x6db60000}, | ||
218 | {0x00016900, 0x11999601}, | ||
219 | {0x00016908, 0x00080010}, | ||
220 | {0x00016944, 0x02084080}, | ||
221 | {0x00016948, 0x000080c0}, | ||
222 | {0x00016b80, 0x00000000}, | ||
223 | {0x00016b84, 0x00000000}, | ||
224 | {0x00016b88, 0x00400705}, | ||
225 | {0x00016b8c, 0x00800700}, | ||
226 | {0x00016b90, 0x00800700}, | ||
227 | {0x00016b94, 0x00000000}, | ||
228 | {0x00016b98, 0x00000000}, | ||
229 | {0x00016b9c, 0x00000000}, | ||
230 | {0x00016ba0, 0x00000001}, | ||
231 | {0x00016ba4, 0x00000001}, | ||
232 | {0x00016ba8, 0x00000000}, | ||
233 | {0x00016bac, 0x00000000}, | ||
234 | {0x00016bb0, 0x00000000}, | ||
235 | {0x00016bb4, 0x00000000}, | ||
236 | {0x00016bb8, 0x00000000}, | ||
237 | {0x00016bbc, 0x00000000}, | ||
238 | {0x00016bc0, 0x000000a0}, | ||
239 | {0x00016bc4, 0x000c0000}, | ||
240 | {0x00016bc8, 0x14021402}, | ||
241 | {0x00016bcc, 0x00001402}, | ||
242 | {0x00016bd0, 0x00000000}, | ||
243 | {0x00016bd4, 0x00000000}, | ||
244 | }; | ||
245 | |||
246 | static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { | ||
247 | /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ | ||
248 | {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | ||
249 | {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | ||
250 | {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | ||
251 | {0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, | ||
252 | {0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da}, | ||
253 | {0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000}, | ||
254 | {0x0000a504, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000002, 0x04000002}, | ||
255 | {0x0000a508, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000004, 0x08000004}, | ||
256 | {0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006}, | ||
257 | {0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a}, | ||
258 | {0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c}, | ||
259 | {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e}, | ||
260 | {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064}, | ||
261 | {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242}, | ||
262 | {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229}, | ||
263 | {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2}, | ||
264 | {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203}, | ||
265 | {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803}, | ||
266 | {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881}, | ||
267 | {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809}, | ||
268 | {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814}, | ||
269 | {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c}, | ||
270 | {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e}, | ||
271 | {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812}, | ||
272 | {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884}, | ||
273 | {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84}, | ||
274 | {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69}, | ||
275 | {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4}, | ||
276 | {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3}, | ||
277 | {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5}, | ||
278 | {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced}, | ||
279 | {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4}, | ||
280 | {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4}, | ||
281 | {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4}, | ||
282 | {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4}, | ||
283 | {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, | ||
284 | {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, | ||
285 | {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
286 | {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
287 | {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
288 | {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000}, | ||
289 | {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02}, | ||
290 | {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04}, | ||
291 | {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000}, | ||
292 | {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000}, | ||
293 | {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000}, | ||
294 | {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000}, | ||
295 | {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05}, | ||
296 | {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06}, | ||
297 | {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07}, | ||
298 | {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07}, | ||
299 | {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07}, | ||
300 | {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07}, | ||
301 | {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | ||
302 | {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | ||
303 | {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | ||
304 | {0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, | ||
305 | {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, | ||
306 | {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, | ||
307 | {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, | ||
308 | {0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, | ||
309 | {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, | ||
310 | {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | ||
311 | {0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84}, | ||
312 | {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, | ||
313 | {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | ||
314 | {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, | ||
315 | {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, | ||
316 | }; | ||
317 | |||
318 | static const u32 ar955x_1p0_mac_core[][2] = { | ||
319 | /* Addr allmodes */ | ||
320 | {0x00000008, 0x00000000}, | ||
321 | {0x00000030, 0x00020085}, | ||
322 | {0x00000034, 0x00000005}, | ||
323 | {0x00000040, 0x00000000}, | ||
324 | {0x00000044, 0x00000000}, | ||
325 | {0x00000048, 0x00000008}, | ||
326 | {0x0000004c, 0x00000010}, | ||
327 | {0x00000050, 0x00000000}, | ||
328 | {0x00001040, 0x002ffc0f}, | ||
329 | {0x00001044, 0x002ffc0f}, | ||
330 | {0x00001048, 0x002ffc0f}, | ||
331 | {0x0000104c, 0x002ffc0f}, | ||
332 | {0x00001050, 0x002ffc0f}, | ||
333 | {0x00001054, 0x002ffc0f}, | ||
334 | {0x00001058, 0x002ffc0f}, | ||
335 | {0x0000105c, 0x002ffc0f}, | ||
336 | {0x00001060, 0x002ffc0f}, | ||
337 | {0x00001064, 0x002ffc0f}, | ||
338 | {0x000010f0, 0x00000100}, | ||
339 | {0x00001270, 0x00000000}, | ||
340 | {0x000012b0, 0x00000000}, | ||
341 | {0x000012f0, 0x00000000}, | ||
342 | {0x0000143c, 0x00000000}, | ||
343 | {0x0000147c, 0x00000000}, | ||
344 | {0x00008000, 0x00000000}, | ||
345 | {0x00008004, 0x00000000}, | ||
346 | {0x00008008, 0x00000000}, | ||
347 | {0x0000800c, 0x00000000}, | ||
348 | {0x00008018, 0x00000000}, | ||
349 | {0x00008020, 0x00000000}, | ||
350 | {0x00008038, 0x00000000}, | ||
351 | {0x0000803c, 0x00000000}, | ||
352 | {0x00008040, 0x00000000}, | ||
353 | {0x00008044, 0x00000000}, | ||
354 | {0x00008048, 0x00000000}, | ||
355 | {0x0000804c, 0xffffffff}, | ||
356 | {0x00008054, 0x00000000}, | ||
357 | {0x00008058, 0x00000000}, | ||
358 | {0x0000805c, 0x000fc78f}, | ||
359 | {0x00008060, 0x0000000f}, | ||
360 | {0x00008064, 0x00000000}, | ||
361 | {0x00008070, 0x00000310}, | ||
362 | {0x00008074, 0x00000020}, | ||
363 | {0x00008078, 0x00000000}, | ||
364 | {0x0000809c, 0x0000000f}, | ||
365 | {0x000080a0, 0x00000000}, | ||
366 | {0x000080a4, 0x02ff0000}, | ||
367 | {0x000080a8, 0x0e070605}, | ||
368 | {0x000080ac, 0x0000000d}, | ||
369 | {0x000080b0, 0x00000000}, | ||
370 | {0x000080b4, 0x00000000}, | ||
371 | {0x000080b8, 0x00000000}, | ||
372 | {0x000080bc, 0x00000000}, | ||
373 | {0x000080c0, 0x2a800000}, | ||
374 | {0x000080c4, 0x06900168}, | ||
375 | {0x000080c8, 0x13881c22}, | ||
376 | {0x000080cc, 0x01f40000}, | ||
377 | {0x000080d0, 0x00252500}, | ||
378 | {0x000080d4, 0x00a00000}, | ||
379 | {0x000080d8, 0x00400000}, | ||
380 | {0x000080dc, 0x00000000}, | ||
381 | {0x000080e0, 0xffffffff}, | ||
382 | {0x000080e4, 0x0000ffff}, | ||
383 | {0x000080e8, 0x3f3f3f3f}, | ||
384 | {0x000080ec, 0x00000000}, | ||
385 | {0x000080f0, 0x00000000}, | ||
386 | {0x000080f4, 0x00000000}, | ||
387 | {0x000080fc, 0x00020000}, | ||
388 | {0x00008100, 0x00000000}, | ||
389 | {0x00008108, 0x00000052}, | ||
390 | {0x0000810c, 0x00000000}, | ||
391 | {0x00008110, 0x00000000}, | ||
392 | {0x00008114, 0x000007ff}, | ||
393 | {0x00008118, 0x000000aa}, | ||
394 | {0x0000811c, 0x00003210}, | ||
395 | {0x00008124, 0x00000000}, | ||
396 | {0x00008128, 0x00000000}, | ||
397 | {0x0000812c, 0x00000000}, | ||
398 | {0x00008130, 0x00000000}, | ||
399 | {0x00008134, 0x00000000}, | ||
400 | {0x00008138, 0x00000000}, | ||
401 | {0x0000813c, 0x0000ffff}, | ||
402 | {0x00008140, 0x000000fe}, | ||
403 | {0x00008144, 0xffffffff}, | ||
404 | {0x00008168, 0x00000000}, | ||
405 | {0x0000816c, 0x00000000}, | ||
406 | {0x000081c0, 0x00000000}, | ||
407 | {0x000081c4, 0x33332210}, | ||
408 | {0x000081ec, 0x00000000}, | ||
409 | {0x000081f0, 0x00000000}, | ||
410 | {0x000081f4, 0x00000000}, | ||
411 | {0x000081f8, 0x00000000}, | ||
412 | {0x000081fc, 0x00000000}, | ||
413 | {0x00008240, 0x00100000}, | ||
414 | {0x00008244, 0x0010f400}, | ||
415 | {0x00008248, 0x00000800}, | ||
416 | {0x0000824c, 0x0001e800}, | ||
417 | {0x00008250, 0x00000000}, | ||
418 | {0x00008254, 0x00000000}, | ||
419 | {0x00008258, 0x00000000}, | ||
420 | {0x0000825c, 0x40000000}, | ||
421 | {0x00008260, 0x00080922}, | ||
422 | {0x00008264, 0x9d400010}, | ||
423 | {0x00008268, 0xffffffff}, | ||
424 | {0x0000826c, 0x0000ffff}, | ||
425 | {0x00008270, 0x00000000}, | ||
426 | {0x00008274, 0x40000000}, | ||
427 | {0x00008278, 0x003e4180}, | ||
428 | {0x0000827c, 0x00000004}, | ||
429 | {0x00008284, 0x0000002c}, | ||
430 | {0x00008288, 0x0000002c}, | ||
431 | {0x0000828c, 0x000000ff}, | ||
432 | {0x00008294, 0x00000000}, | ||
433 | {0x00008298, 0x00000000}, | ||
434 | {0x0000829c, 0x00000000}, | ||
435 | {0x00008300, 0x00001d40}, | ||
436 | {0x00008314, 0x00000000}, | ||
437 | {0x0000831c, 0x0000010d}, | ||
438 | {0x00008328, 0x00000000}, | ||
439 | {0x0000832c, 0x0000001f}, | ||
440 | {0x00008330, 0x00000302}, | ||
441 | {0x00008334, 0x00000700}, | ||
442 | {0x00008338, 0xffff0000}, | ||
443 | {0x0000833c, 0x02400000}, | ||
444 | {0x00008340, 0x000107ff}, | ||
445 | {0x00008344, 0xaa48107b}, | ||
446 | {0x00008348, 0x008f0000}, | ||
447 | {0x0000835c, 0x00000000}, | ||
448 | {0x00008360, 0xffffffff}, | ||
449 | {0x00008364, 0xffffffff}, | ||
450 | {0x00008368, 0x00000000}, | ||
451 | {0x00008370, 0x00000000}, | ||
452 | {0x00008374, 0x000000ff}, | ||
453 | {0x00008378, 0x00000000}, | ||
454 | {0x0000837c, 0x00000000}, | ||
455 | {0x00008380, 0xffffffff}, | ||
456 | {0x00008384, 0xffffffff}, | ||
457 | {0x00008390, 0xffffffff}, | ||
458 | {0x00008394, 0xffffffff}, | ||
459 | {0x00008398, 0x00000000}, | ||
460 | {0x0000839c, 0x00000000}, | ||
461 | {0x000083a0, 0x00000000}, | ||
462 | {0x000083a4, 0x0000fa14}, | ||
463 | {0x000083a8, 0x000f0c00}, | ||
464 | {0x000083ac, 0x33332210}, | ||
465 | {0x000083b0, 0x33332210}, | ||
466 | {0x000083b4, 0x33332210}, | ||
467 | {0x000083b8, 0x33332210}, | ||
468 | {0x000083bc, 0x00000000}, | ||
469 | {0x000083c0, 0x00000000}, | ||
470 | {0x000083c4, 0x00000000}, | ||
471 | {0x000083c8, 0x00000000}, | ||
472 | {0x000083cc, 0x00000200}, | ||
473 | {0x000083d0, 0x8c7901ff}, | ||
474 | }; | ||
475 | |||
476 | static const u32 ar955x_1p0_common_rx_gain_table[][2] = { | ||
477 | /* Addr allmodes */ | ||
478 | {0x0000a000, 0x00010000}, | ||
479 | {0x0000a004, 0x00030002}, | ||
480 | {0x0000a008, 0x00050004}, | ||
481 | {0x0000a00c, 0x00810080}, | ||
482 | {0x0000a010, 0x00830082}, | ||
483 | {0x0000a014, 0x01810180}, | ||
484 | {0x0000a018, 0x01830182}, | ||
485 | {0x0000a01c, 0x01850184}, | ||
486 | {0x0000a020, 0x01890188}, | ||
487 | {0x0000a024, 0x018b018a}, | ||
488 | {0x0000a028, 0x018d018c}, | ||
489 | {0x0000a02c, 0x01910190}, | ||
490 | {0x0000a030, 0x01930192}, | ||
491 | {0x0000a034, 0x01950194}, | ||
492 | {0x0000a038, 0x038a0196}, | ||
493 | {0x0000a03c, 0x038c038b}, | ||
494 | {0x0000a040, 0x0390038d}, | ||
495 | {0x0000a044, 0x03920391}, | ||
496 | {0x0000a048, 0x03940393}, | ||
497 | {0x0000a04c, 0x03960395}, | ||
498 | {0x0000a050, 0x00000000}, | ||
499 | {0x0000a054, 0x00000000}, | ||
500 | {0x0000a058, 0x00000000}, | ||
501 | {0x0000a05c, 0x00000000}, | ||
502 | {0x0000a060, 0x00000000}, | ||
503 | {0x0000a064, 0x00000000}, | ||
504 | {0x0000a068, 0x00000000}, | ||
505 | {0x0000a06c, 0x00000000}, | ||
506 | {0x0000a070, 0x00000000}, | ||
507 | {0x0000a074, 0x00000000}, | ||
508 | {0x0000a078, 0x00000000}, | ||
509 | {0x0000a07c, 0x00000000}, | ||
510 | {0x0000a080, 0x22222229}, | ||
511 | {0x0000a084, 0x1d1d1d1d}, | ||
512 | {0x0000a088, 0x1d1d1d1d}, | ||
513 | {0x0000a08c, 0x1d1d1d1d}, | ||
514 | {0x0000a090, 0x171d1d1d}, | ||
515 | {0x0000a094, 0x11111717}, | ||
516 | {0x0000a098, 0x00030311}, | ||
517 | {0x0000a09c, 0x00000000}, | ||
518 | {0x0000a0a0, 0x00000000}, | ||
519 | {0x0000a0a4, 0x00000000}, | ||
520 | {0x0000a0a8, 0x00000000}, | ||
521 | {0x0000a0ac, 0x00000000}, | ||
522 | {0x0000a0b0, 0x00000000}, | ||
523 | {0x0000a0b4, 0x00000000}, | ||
524 | {0x0000a0b8, 0x00000000}, | ||
525 | {0x0000a0bc, 0x00000000}, | ||
526 | {0x0000a0c0, 0x001f0000}, | ||
527 | {0x0000a0c4, 0x01000101}, | ||
528 | {0x0000a0c8, 0x011e011f}, | ||
529 | {0x0000a0cc, 0x011c011d}, | ||
530 | {0x0000a0d0, 0x02030204}, | ||
531 | {0x0000a0d4, 0x02010202}, | ||
532 | {0x0000a0d8, 0x021f0200}, | ||
533 | {0x0000a0dc, 0x0302021e}, | ||
534 | {0x0000a0e0, 0x03000301}, | ||
535 | {0x0000a0e4, 0x031e031f}, | ||
536 | {0x0000a0e8, 0x0402031d}, | ||
537 | {0x0000a0ec, 0x04000401}, | ||
538 | {0x0000a0f0, 0x041e041f}, | ||
539 | {0x0000a0f4, 0x0502041d}, | ||
540 | {0x0000a0f8, 0x05000501}, | ||
541 | {0x0000a0fc, 0x051e051f}, | ||
542 | {0x0000a100, 0x06010602}, | ||
543 | {0x0000a104, 0x061f0600}, | ||
544 | {0x0000a108, 0x061d061e}, | ||
545 | {0x0000a10c, 0x07020703}, | ||
546 | {0x0000a110, 0x07000701}, | ||
547 | {0x0000a114, 0x00000000}, | ||
548 | {0x0000a118, 0x00000000}, | ||
549 | {0x0000a11c, 0x00000000}, | ||
550 | {0x0000a120, 0x00000000}, | ||
551 | {0x0000a124, 0x00000000}, | ||
552 | {0x0000a128, 0x00000000}, | ||
553 | {0x0000a12c, 0x00000000}, | ||
554 | {0x0000a130, 0x00000000}, | ||
555 | {0x0000a134, 0x00000000}, | ||
556 | {0x0000a138, 0x00000000}, | ||
557 | {0x0000a13c, 0x00000000}, | ||
558 | {0x0000a140, 0x001f0000}, | ||
559 | {0x0000a144, 0x01000101}, | ||
560 | {0x0000a148, 0x011e011f}, | ||
561 | {0x0000a14c, 0x011c011d}, | ||
562 | {0x0000a150, 0x02030204}, | ||
563 | {0x0000a154, 0x02010202}, | ||
564 | {0x0000a158, 0x021f0200}, | ||
565 | {0x0000a15c, 0x0302021e}, | ||
566 | {0x0000a160, 0x03000301}, | ||
567 | {0x0000a164, 0x031e031f}, | ||
568 | {0x0000a168, 0x0402031d}, | ||
569 | {0x0000a16c, 0x04000401}, | ||
570 | {0x0000a170, 0x041e041f}, | ||
571 | {0x0000a174, 0x0502041d}, | ||
572 | {0x0000a178, 0x05000501}, | ||
573 | {0x0000a17c, 0x051e051f}, | ||
574 | {0x0000a180, 0x06010602}, | ||
575 | {0x0000a184, 0x061f0600}, | ||
576 | {0x0000a188, 0x061d061e}, | ||
577 | {0x0000a18c, 0x07020703}, | ||
578 | {0x0000a190, 0x07000701}, | ||
579 | {0x0000a194, 0x00000000}, | ||
580 | {0x0000a198, 0x00000000}, | ||
581 | {0x0000a19c, 0x00000000}, | ||
582 | {0x0000a1a0, 0x00000000}, | ||
583 | {0x0000a1a4, 0x00000000}, | ||
584 | {0x0000a1a8, 0x00000000}, | ||
585 | {0x0000a1ac, 0x00000000}, | ||
586 | {0x0000a1b0, 0x00000000}, | ||
587 | {0x0000a1b4, 0x00000000}, | ||
588 | {0x0000a1b8, 0x00000000}, | ||
589 | {0x0000a1bc, 0x00000000}, | ||
590 | {0x0000a1c0, 0x00000000}, | ||
591 | {0x0000a1c4, 0x00000000}, | ||
592 | {0x0000a1c8, 0x00000000}, | ||
593 | {0x0000a1cc, 0x00000000}, | ||
594 | {0x0000a1d0, 0x00000000}, | ||
595 | {0x0000a1d4, 0x00000000}, | ||
596 | {0x0000a1d8, 0x00000000}, | ||
597 | {0x0000a1dc, 0x00000000}, | ||
598 | {0x0000a1e0, 0x00000000}, | ||
599 | {0x0000a1e4, 0x00000000}, | ||
600 | {0x0000a1e8, 0x00000000}, | ||
601 | {0x0000a1ec, 0x00000000}, | ||
602 | {0x0000a1f0, 0x00000396}, | ||
603 | {0x0000a1f4, 0x00000396}, | ||
604 | {0x0000a1f8, 0x00000396}, | ||
605 | {0x0000a1fc, 0x00000196}, | ||
606 | {0x0000b000, 0x00010000}, | ||
607 | {0x0000b004, 0x00030002}, | ||
608 | {0x0000b008, 0x00050004}, | ||
609 | {0x0000b00c, 0x00810080}, | ||
610 | {0x0000b010, 0x00830082}, | ||
611 | {0x0000b014, 0x01810180}, | ||
612 | {0x0000b018, 0x01830182}, | ||
613 | {0x0000b01c, 0x01850184}, | ||
614 | {0x0000b020, 0x02810280}, | ||
615 | {0x0000b024, 0x02830282}, | ||
616 | {0x0000b028, 0x02850284}, | ||
617 | {0x0000b02c, 0x02890288}, | ||
618 | {0x0000b030, 0x028b028a}, | ||
619 | {0x0000b034, 0x0388028c}, | ||
620 | {0x0000b038, 0x038a0389}, | ||
621 | {0x0000b03c, 0x038c038b}, | ||
622 | {0x0000b040, 0x0390038d}, | ||
623 | {0x0000b044, 0x03920391}, | ||
624 | {0x0000b048, 0x03940393}, | ||
625 | {0x0000b04c, 0x03960395}, | ||
626 | {0x0000b050, 0x00000000}, | ||
627 | {0x0000b054, 0x00000000}, | ||
628 | {0x0000b058, 0x00000000}, | ||
629 | {0x0000b05c, 0x00000000}, | ||
630 | {0x0000b060, 0x00000000}, | ||
631 | {0x0000b064, 0x00000000}, | ||
632 | {0x0000b068, 0x00000000}, | ||
633 | {0x0000b06c, 0x00000000}, | ||
634 | {0x0000b070, 0x00000000}, | ||
635 | {0x0000b074, 0x00000000}, | ||
636 | {0x0000b078, 0x00000000}, | ||
637 | {0x0000b07c, 0x00000000}, | ||
638 | {0x0000b080, 0x23232323}, | ||
639 | {0x0000b084, 0x21232323}, | ||
640 | {0x0000b088, 0x19191c1e}, | ||
641 | {0x0000b08c, 0x12141417}, | ||
642 | {0x0000b090, 0x07070e0e}, | ||
643 | {0x0000b094, 0x03030305}, | ||
644 | {0x0000b098, 0x00000003}, | ||
645 | {0x0000b09c, 0x00000000}, | ||
646 | {0x0000b0a0, 0x00000000}, | ||
647 | {0x0000b0a4, 0x00000000}, | ||
648 | {0x0000b0a8, 0x00000000}, | ||
649 | {0x0000b0ac, 0x00000000}, | ||
650 | {0x0000b0b0, 0x00000000}, | ||
651 | {0x0000b0b4, 0x00000000}, | ||
652 | {0x0000b0b8, 0x00000000}, | ||
653 | {0x0000b0bc, 0x00000000}, | ||
654 | {0x0000b0c0, 0x003f0020}, | ||
655 | {0x0000b0c4, 0x00400041}, | ||
656 | {0x0000b0c8, 0x0140005f}, | ||
657 | {0x0000b0cc, 0x0160015f}, | ||
658 | {0x0000b0d0, 0x017e017f}, | ||
659 | {0x0000b0d4, 0x02410242}, | ||
660 | {0x0000b0d8, 0x025f0240}, | ||
661 | {0x0000b0dc, 0x027f0260}, | ||
662 | {0x0000b0e0, 0x0341027e}, | ||
663 | {0x0000b0e4, 0x035f0340}, | ||
664 | {0x0000b0e8, 0x037f0360}, | ||
665 | {0x0000b0ec, 0x04400441}, | ||
666 | {0x0000b0f0, 0x0460045f}, | ||
667 | {0x0000b0f4, 0x0541047f}, | ||
668 | {0x0000b0f8, 0x055f0540}, | ||
669 | {0x0000b0fc, 0x057f0560}, | ||
670 | {0x0000b100, 0x06400641}, | ||
671 | {0x0000b104, 0x0660065f}, | ||
672 | {0x0000b108, 0x067e067f}, | ||
673 | {0x0000b10c, 0x07410742}, | ||
674 | {0x0000b110, 0x075f0740}, | ||
675 | {0x0000b114, 0x077f0760}, | ||
676 | {0x0000b118, 0x07800781}, | ||
677 | {0x0000b11c, 0x07a0079f}, | ||
678 | {0x0000b120, 0x07c107bf}, | ||
679 | {0x0000b124, 0x000007c0}, | ||
680 | {0x0000b128, 0x00000000}, | ||
681 | {0x0000b12c, 0x00000000}, | ||
682 | {0x0000b130, 0x00000000}, | ||
683 | {0x0000b134, 0x00000000}, | ||
684 | {0x0000b138, 0x00000000}, | ||
685 | {0x0000b13c, 0x00000000}, | ||
686 | {0x0000b140, 0x003f0020}, | ||
687 | {0x0000b144, 0x00400041}, | ||
688 | {0x0000b148, 0x0140005f}, | ||
689 | {0x0000b14c, 0x0160015f}, | ||
690 | {0x0000b150, 0x017e017f}, | ||
691 | {0x0000b154, 0x02410242}, | ||
692 | {0x0000b158, 0x025f0240}, | ||
693 | {0x0000b15c, 0x027f0260}, | ||
694 | {0x0000b160, 0x0341027e}, | ||
695 | {0x0000b164, 0x035f0340}, | ||
696 | {0x0000b168, 0x037f0360}, | ||
697 | {0x0000b16c, 0x04400441}, | ||
698 | {0x0000b170, 0x0460045f}, | ||
699 | {0x0000b174, 0x0541047f}, | ||
700 | {0x0000b178, 0x055f0540}, | ||
701 | {0x0000b17c, 0x057f0560}, | ||
702 | {0x0000b180, 0x06400641}, | ||
703 | {0x0000b184, 0x0660065f}, | ||
704 | {0x0000b188, 0x067e067f}, | ||
705 | {0x0000b18c, 0x07410742}, | ||
706 | {0x0000b190, 0x075f0740}, | ||
707 | {0x0000b194, 0x077f0760}, | ||
708 | {0x0000b198, 0x07800781}, | ||
709 | {0x0000b19c, 0x07a0079f}, | ||
710 | {0x0000b1a0, 0x07c107bf}, | ||
711 | {0x0000b1a4, 0x000007c0}, | ||
712 | {0x0000b1a8, 0x00000000}, | ||
713 | {0x0000b1ac, 0x00000000}, | ||
714 | {0x0000b1b0, 0x00000000}, | ||
715 | {0x0000b1b4, 0x00000000}, | ||
716 | {0x0000b1b8, 0x00000000}, | ||
717 | {0x0000b1bc, 0x00000000}, | ||
718 | {0x0000b1c0, 0x00000000}, | ||
719 | {0x0000b1c4, 0x00000000}, | ||
720 | {0x0000b1c8, 0x00000000}, | ||
721 | {0x0000b1cc, 0x00000000}, | ||
722 | {0x0000b1d0, 0x00000000}, | ||
723 | {0x0000b1d4, 0x00000000}, | ||
724 | {0x0000b1d8, 0x00000000}, | ||
725 | {0x0000b1dc, 0x00000000}, | ||
726 | {0x0000b1e0, 0x00000000}, | ||
727 | {0x0000b1e4, 0x00000000}, | ||
728 | {0x0000b1e8, 0x00000000}, | ||
729 | {0x0000b1ec, 0x00000000}, | ||
730 | {0x0000b1f0, 0x00000396}, | ||
731 | {0x0000b1f4, 0x00000396}, | ||
732 | {0x0000b1f8, 0x00000396}, | ||
733 | {0x0000b1fc, 0x00000196}, | ||
734 | }; | ||
735 | |||
736 | static const u32 ar955x_1p0_baseband_core[][2] = { | ||
737 | /* Addr allmodes */ | ||
738 | {0x00009800, 0xafe68e30}, | ||
739 | {0x00009804, 0xfd14e000}, | ||
740 | {0x00009808, 0x9c0a9f6b}, | ||
741 | {0x0000980c, 0x04900000}, | ||
742 | {0x00009814, 0x0280c00a}, | ||
743 | {0x00009818, 0x00000000}, | ||
744 | {0x0000981c, 0x00020028}, | ||
745 | {0x00009834, 0x6400a190}, | ||
746 | {0x00009838, 0x0108ecff}, | ||
747 | {0x0000983c, 0x14000600}, | ||
748 | {0x00009880, 0x201fff00}, | ||
749 | {0x00009884, 0x00001042}, | ||
750 | {0x000098a4, 0x00200400}, | ||
751 | {0x000098b0, 0x32840bbe}, | ||
752 | {0x000098bc, 0x00000002}, | ||
753 | {0x000098d0, 0x004b6a8e}, | ||
754 | {0x000098d4, 0x00000820}, | ||
755 | {0x000098dc, 0x00000000}, | ||
756 | {0x000098f0, 0x00000000}, | ||
757 | {0x000098f4, 0x00000000}, | ||
758 | {0x00009c04, 0xff55ff55}, | ||
759 | {0x00009c08, 0x0320ff55}, | ||
760 | {0x00009c0c, 0x00000000}, | ||
761 | {0x00009c10, 0x00000000}, | ||
762 | {0x00009c14, 0x00046384}, | ||
763 | {0x00009c18, 0x05b6b440}, | ||
764 | {0x00009c1c, 0x00b6b440}, | ||
765 | {0x00009d00, 0xc080a333}, | ||
766 | {0x00009d04, 0x40206c10}, | ||
767 | {0x00009d08, 0x009c4060}, | ||
768 | {0x00009d0c, 0x9883800a}, | ||
769 | {0x00009d10, 0x01834061}, | ||
770 | {0x00009d14, 0x00c0040b}, | ||
771 | {0x00009d18, 0x00000000}, | ||
772 | {0x00009e08, 0x0038230c}, | ||
773 | {0x00009e24, 0x990bb515}, | ||
774 | {0x00009e28, 0x0c6f0000}, | ||
775 | {0x00009e30, 0x06336f77}, | ||
776 | {0x00009e34, 0x6af6532f}, | ||
777 | {0x00009e38, 0x0cc80c00}, | ||
778 | {0x00009e40, 0x0d261820}, | ||
779 | {0x00009e4c, 0x00001004}, | ||
780 | {0x00009e50, 0x00ff03f1}, | ||
781 | {0x00009fc0, 0x813e4788}, | ||
782 | {0x00009fc4, 0x0001efb5}, | ||
783 | {0x00009fcc, 0x40000014}, | ||
784 | {0x00009fd0, 0x01193b93}, | ||
785 | {0x0000a20c, 0x00000000}, | ||
786 | {0x0000a220, 0x00000000}, | ||
787 | {0x0000a224, 0x00000000}, | ||
788 | {0x0000a228, 0x10002310}, | ||
789 | {0x0000a23c, 0x00000000}, | ||
790 | {0x0000a244, 0x0c000000}, | ||
791 | {0x0000a248, 0x00000140}, | ||
792 | {0x0000a2a0, 0x00000007}, | ||
793 | {0x0000a2c0, 0x00000007}, | ||
794 | {0x0000a2c8, 0x00000000}, | ||
795 | {0x0000a2d4, 0x00000000}, | ||
796 | {0x0000a2ec, 0x00000000}, | ||
797 | {0x0000a2f0, 0x00000000}, | ||
798 | {0x0000a2f4, 0x00000000}, | ||
799 | {0x0000a2f8, 0x00000000}, | ||
800 | {0x0000a344, 0x00000000}, | ||
801 | {0x0000a34c, 0x00000000}, | ||
802 | {0x0000a350, 0x0000a000}, | ||
803 | {0x0000a364, 0x00000000}, | ||
804 | {0x0000a370, 0x00000000}, | ||
805 | {0x0000a390, 0x00000001}, | ||
806 | {0x0000a394, 0x00000444}, | ||
807 | {0x0000a398, 0x1f020503}, | ||
808 | {0x0000a39c, 0x29180c03}, | ||
809 | {0x0000a3a0, 0x9a8b6844}, | ||
810 | {0x0000a3a4, 0x00000000}, | ||
811 | {0x0000a3a8, 0xaaaaaaaa}, | ||
812 | {0x0000a3ac, 0x3c466478}, | ||
813 | {0x0000a3c0, 0x20202020}, | ||
814 | {0x0000a3c4, 0x22222220}, | ||
815 | {0x0000a3c8, 0x20200020}, | ||
816 | {0x0000a3cc, 0x20202020}, | ||
817 | {0x0000a3d0, 0x20202020}, | ||
818 | {0x0000a3d4, 0x20202020}, | ||
819 | {0x0000a3d8, 0x20202020}, | ||
820 | {0x0000a3dc, 0x20202020}, | ||
821 | {0x0000a3e0, 0x20202020}, | ||
822 | {0x0000a3e4, 0x20202020}, | ||
823 | {0x0000a3e8, 0x20202020}, | ||
824 | {0x0000a3ec, 0x20202020}, | ||
825 | {0x0000a3f0, 0x00000000}, | ||
826 | {0x0000a3f4, 0x00000000}, | ||
827 | {0x0000a3f8, 0x0c9bd380}, | ||
828 | {0x0000a3fc, 0x000f0f01}, | ||
829 | {0x0000a400, 0x8fa91f01}, | ||
830 | {0x0000a404, 0x00000000}, | ||
831 | {0x0000a408, 0x0e79e5c6}, | ||
832 | {0x0000a40c, 0x00820820}, | ||
833 | {0x0000a414, 0x1ce739ce}, | ||
834 | {0x0000a418, 0x2d001dce}, | ||
835 | {0x0000a41c, 0x1ce739ce}, | ||
836 | {0x0000a420, 0x000001ce}, | ||
837 | {0x0000a424, 0x1ce739ce}, | ||
838 | {0x0000a428, 0x000001ce}, | ||
839 | {0x0000a42c, 0x1ce739ce}, | ||
840 | {0x0000a430, 0x1ce739ce}, | ||
841 | {0x0000a434, 0x00000000}, | ||
842 | {0x0000a438, 0x00001801}, | ||
843 | {0x0000a43c, 0x00100000}, | ||
844 | {0x0000a444, 0x00000000}, | ||
845 | {0x0000a448, 0x05000080}, | ||
846 | {0x0000a44c, 0x00000001}, | ||
847 | {0x0000a450, 0x00010000}, | ||
848 | {0x0000a458, 0x00000000}, | ||
849 | {0x0000a644, 0x3fad9d74}, | ||
850 | {0x0000a648, 0x0048060a}, | ||
851 | {0x0000a64c, 0x00003c37}, | ||
852 | {0x0000a670, 0x03020100}, | ||
853 | {0x0000a674, 0x09080504}, | ||
854 | {0x0000a678, 0x0d0c0b0a}, | ||
855 | {0x0000a67c, 0x13121110}, | ||
856 | {0x0000a680, 0x31301514}, | ||
857 | {0x0000a684, 0x35343332}, | ||
858 | {0x0000a688, 0x00000036}, | ||
859 | {0x0000a690, 0x00000838}, | ||
860 | {0x0000a7cc, 0x00000000}, | ||
861 | {0x0000a7d0, 0x00000000}, | ||
862 | {0x0000a7d4, 0x00000004}, | ||
863 | {0x0000a7dc, 0x00000000}, | ||
864 | {0x0000a8d0, 0x004b6a8e}, | ||
865 | {0x0000a8d4, 0x00000820}, | ||
866 | {0x0000a8dc, 0x00000000}, | ||
867 | {0x0000a8f0, 0x00000000}, | ||
868 | {0x0000a8f4, 0x00000000}, | ||
869 | {0x0000b2d0, 0x00000080}, | ||
870 | {0x0000b2d4, 0x00000000}, | ||
871 | {0x0000b2ec, 0x00000000}, | ||
872 | {0x0000b2f0, 0x00000000}, | ||
873 | {0x0000b2f4, 0x00000000}, | ||
874 | {0x0000b2f8, 0x00000000}, | ||
875 | {0x0000b408, 0x0e79e5c0}, | ||
876 | {0x0000b40c, 0x00820820}, | ||
877 | {0x0000b420, 0x00000000}, | ||
878 | {0x0000b8d0, 0x004b6a8e}, | ||
879 | {0x0000b8d4, 0x00000820}, | ||
880 | {0x0000b8dc, 0x00000000}, | ||
881 | {0x0000b8f0, 0x00000000}, | ||
882 | {0x0000b8f4, 0x00000000}, | ||
883 | {0x0000c2d0, 0x00000080}, | ||
884 | {0x0000c2d4, 0x00000000}, | ||
885 | {0x0000c2ec, 0x00000000}, | ||
886 | {0x0000c2f0, 0x00000000}, | ||
887 | {0x0000c2f4, 0x00000000}, | ||
888 | {0x0000c2f8, 0x00000000}, | ||
889 | {0x0000c408, 0x0e79e5c0}, | ||
890 | {0x0000c40c, 0x00820820}, | ||
891 | {0x0000c420, 0x00000000}, | ||
892 | }; | ||
893 | |||
894 | static const u32 ar955x_1p0_common_wo_xlna_rx_gain_table[][2] = { | ||
895 | /* Addr allmodes */ | ||
896 | {0x0000a000, 0x00010000}, | ||
897 | {0x0000a004, 0x00030002}, | ||
898 | {0x0000a008, 0x00050004}, | ||
899 | {0x0000a00c, 0x00810080}, | ||
900 | {0x0000a010, 0x00830082}, | ||
901 | {0x0000a014, 0x01810180}, | ||
902 | {0x0000a018, 0x01830182}, | ||
903 | {0x0000a01c, 0x01850184}, | ||
904 | {0x0000a020, 0x01890188}, | ||
905 | {0x0000a024, 0x018b018a}, | ||
906 | {0x0000a028, 0x018d018c}, | ||
907 | {0x0000a02c, 0x03820190}, | ||
908 | {0x0000a030, 0x03840383}, | ||
909 | {0x0000a034, 0x03880385}, | ||
910 | {0x0000a038, 0x038a0389}, | ||
911 | {0x0000a03c, 0x038c038b}, | ||
912 | {0x0000a040, 0x0390038d}, | ||
913 | {0x0000a044, 0x03920391}, | ||
914 | {0x0000a048, 0x03940393}, | ||
915 | {0x0000a04c, 0x03960395}, | ||
916 | {0x0000a050, 0x00000000}, | ||
917 | {0x0000a054, 0x00000000}, | ||
918 | {0x0000a058, 0x00000000}, | ||
919 | {0x0000a05c, 0x00000000}, | ||
920 | {0x0000a060, 0x00000000}, | ||
921 | {0x0000a064, 0x00000000}, | ||
922 | {0x0000a068, 0x00000000}, | ||
923 | {0x0000a06c, 0x00000000}, | ||
924 | {0x0000a070, 0x00000000}, | ||
925 | {0x0000a074, 0x00000000}, | ||
926 | {0x0000a078, 0x00000000}, | ||
927 | {0x0000a07c, 0x00000000}, | ||
928 | {0x0000a080, 0x29292929}, | ||
929 | {0x0000a084, 0x29292929}, | ||
930 | {0x0000a088, 0x29292929}, | ||
931 | {0x0000a08c, 0x29292929}, | ||
932 | {0x0000a090, 0x22292929}, | ||
933 | {0x0000a094, 0x1d1d2222}, | ||
934 | {0x0000a098, 0x0c111117}, | ||
935 | {0x0000a09c, 0x00030303}, | ||
936 | {0x0000a0a0, 0x00000000}, | ||
937 | {0x0000a0a4, 0x00000000}, | ||
938 | {0x0000a0a8, 0x00000000}, | ||
939 | {0x0000a0ac, 0x00000000}, | ||
940 | {0x0000a0b0, 0x00000000}, | ||
941 | {0x0000a0b4, 0x00000000}, | ||
942 | {0x0000a0b8, 0x00000000}, | ||
943 | {0x0000a0bc, 0x00000000}, | ||
944 | {0x0000a0c0, 0x001f0000}, | ||
945 | {0x0000a0c4, 0x01000101}, | ||
946 | {0x0000a0c8, 0x011e011f}, | ||
947 | {0x0000a0cc, 0x011c011d}, | ||
948 | {0x0000a0d0, 0x02030204}, | ||
949 | {0x0000a0d4, 0x02010202}, | ||
950 | {0x0000a0d8, 0x021f0200}, | ||
951 | {0x0000a0dc, 0x0302021e}, | ||
952 | {0x0000a0e0, 0x03000301}, | ||
953 | {0x0000a0e4, 0x031e031f}, | ||
954 | {0x0000a0e8, 0x0402031d}, | ||
955 | {0x0000a0ec, 0x04000401}, | ||
956 | {0x0000a0f0, 0x041e041f}, | ||
957 | {0x0000a0f4, 0x0502041d}, | ||
958 | {0x0000a0f8, 0x05000501}, | ||
959 | {0x0000a0fc, 0x051e051f}, | ||
960 | {0x0000a100, 0x06010602}, | ||
961 | {0x0000a104, 0x061f0600}, | ||
962 | {0x0000a108, 0x061d061e}, | ||
963 | {0x0000a10c, 0x07020703}, | ||
964 | {0x0000a110, 0x07000701}, | ||
965 | {0x0000a114, 0x00000000}, | ||
966 | {0x0000a118, 0x00000000}, | ||
967 | {0x0000a11c, 0x00000000}, | ||
968 | {0x0000a120, 0x00000000}, | ||
969 | {0x0000a124, 0x00000000}, | ||
970 | {0x0000a128, 0x00000000}, | ||
971 | {0x0000a12c, 0x00000000}, | ||
972 | {0x0000a130, 0x00000000}, | ||
973 | {0x0000a134, 0x00000000}, | ||
974 | {0x0000a138, 0x00000000}, | ||
975 | {0x0000a13c, 0x00000000}, | ||
976 | {0x0000a140, 0x001f0000}, | ||
977 | {0x0000a144, 0x01000101}, | ||
978 | {0x0000a148, 0x011e011f}, | ||
979 | {0x0000a14c, 0x011c011d}, | ||
980 | {0x0000a150, 0x02030204}, | ||
981 | {0x0000a154, 0x02010202}, | ||
982 | {0x0000a158, 0x021f0200}, | ||
983 | {0x0000a15c, 0x0302021e}, | ||
984 | {0x0000a160, 0x03000301}, | ||
985 | {0x0000a164, 0x031e031f}, | ||
986 | {0x0000a168, 0x0402031d}, | ||
987 | {0x0000a16c, 0x04000401}, | ||
988 | {0x0000a170, 0x041e041f}, | ||
989 | {0x0000a174, 0x0502041d}, | ||
990 | {0x0000a178, 0x05000501}, | ||
991 | {0x0000a17c, 0x051e051f}, | ||
992 | {0x0000a180, 0x06010602}, | ||
993 | {0x0000a184, 0x061f0600}, | ||
994 | {0x0000a188, 0x061d061e}, | ||
995 | {0x0000a18c, 0x07020703}, | ||
996 | {0x0000a190, 0x07000701}, | ||
997 | {0x0000a194, 0x00000000}, | ||
998 | {0x0000a198, 0x00000000}, | ||
999 | {0x0000a19c, 0x00000000}, | ||
1000 | {0x0000a1a0, 0x00000000}, | ||
1001 | {0x0000a1a4, 0x00000000}, | ||
1002 | {0x0000a1a8, 0x00000000}, | ||
1003 | {0x0000a1ac, 0x00000000}, | ||
1004 | {0x0000a1b0, 0x00000000}, | ||
1005 | {0x0000a1b4, 0x00000000}, | ||
1006 | {0x0000a1b8, 0x00000000}, | ||
1007 | {0x0000a1bc, 0x00000000}, | ||
1008 | {0x0000a1c0, 0x00000000}, | ||
1009 | {0x0000a1c4, 0x00000000}, | ||
1010 | {0x0000a1c8, 0x00000000}, | ||
1011 | {0x0000a1cc, 0x00000000}, | ||
1012 | {0x0000a1d0, 0x00000000}, | ||
1013 | {0x0000a1d4, 0x00000000}, | ||
1014 | {0x0000a1d8, 0x00000000}, | ||
1015 | {0x0000a1dc, 0x00000000}, | ||
1016 | {0x0000a1e0, 0x00000000}, | ||
1017 | {0x0000a1e4, 0x00000000}, | ||
1018 | {0x0000a1e8, 0x00000000}, | ||
1019 | {0x0000a1ec, 0x00000000}, | ||
1020 | {0x0000a1f0, 0x00000396}, | ||
1021 | {0x0000a1f4, 0x00000396}, | ||
1022 | {0x0000a1f8, 0x00000396}, | ||
1023 | {0x0000a1fc, 0x00000196}, | ||
1024 | {0x0000b000, 0x00010000}, | ||
1025 | {0x0000b004, 0x00030002}, | ||
1026 | {0x0000b008, 0x00050004}, | ||
1027 | {0x0000b00c, 0x00810080}, | ||
1028 | {0x0000b010, 0x00830082}, | ||
1029 | {0x0000b014, 0x01810180}, | ||
1030 | {0x0000b018, 0x01830182}, | ||
1031 | {0x0000b01c, 0x01850184}, | ||
1032 | {0x0000b020, 0x02810280}, | ||
1033 | {0x0000b024, 0x02830282}, | ||
1034 | {0x0000b028, 0x02850284}, | ||
1035 | {0x0000b02c, 0x02890288}, | ||
1036 | {0x0000b030, 0x028b028a}, | ||
1037 | {0x0000b034, 0x0388028c}, | ||
1038 | {0x0000b038, 0x038a0389}, | ||
1039 | {0x0000b03c, 0x038c038b}, | ||
1040 | {0x0000b040, 0x0390038d}, | ||
1041 | {0x0000b044, 0x03920391}, | ||
1042 | {0x0000b048, 0x03940393}, | ||
1043 | {0x0000b04c, 0x03960395}, | ||
1044 | {0x0000b050, 0x00000000}, | ||
1045 | {0x0000b054, 0x00000000}, | ||
1046 | {0x0000b058, 0x00000000}, | ||
1047 | {0x0000b05c, 0x00000000}, | ||
1048 | {0x0000b060, 0x00000000}, | ||
1049 | {0x0000b064, 0x00000000}, | ||
1050 | {0x0000b068, 0x00000000}, | ||
1051 | {0x0000b06c, 0x00000000}, | ||
1052 | {0x0000b070, 0x00000000}, | ||
1053 | {0x0000b074, 0x00000000}, | ||
1054 | {0x0000b078, 0x00000000}, | ||
1055 | {0x0000b07c, 0x00000000}, | ||
1056 | {0x0000b080, 0x32323232}, | ||
1057 | {0x0000b084, 0x2f2f3232}, | ||
1058 | {0x0000b088, 0x23282a2d}, | ||
1059 | {0x0000b08c, 0x1c1e2123}, | ||
1060 | {0x0000b090, 0x14171919}, | ||
1061 | {0x0000b094, 0x0e0e1214}, | ||
1062 | {0x0000b098, 0x03050707}, | ||
1063 | {0x0000b09c, 0x00030303}, | ||
1064 | {0x0000b0a0, 0x00000000}, | ||
1065 | {0x0000b0a4, 0x00000000}, | ||
1066 | {0x0000b0a8, 0x00000000}, | ||
1067 | {0x0000b0ac, 0x00000000}, | ||
1068 | {0x0000b0b0, 0x00000000}, | ||
1069 | {0x0000b0b4, 0x00000000}, | ||
1070 | {0x0000b0b8, 0x00000000}, | ||
1071 | {0x0000b0bc, 0x00000000}, | ||
1072 | {0x0000b0c0, 0x003f0020}, | ||
1073 | {0x0000b0c4, 0x00400041}, | ||
1074 | {0x0000b0c8, 0x0140005f}, | ||
1075 | {0x0000b0cc, 0x0160015f}, | ||
1076 | {0x0000b0d0, 0x017e017f}, | ||
1077 | {0x0000b0d4, 0x02410242}, | ||
1078 | {0x0000b0d8, 0x025f0240}, | ||
1079 | {0x0000b0dc, 0x027f0260}, | ||
1080 | {0x0000b0e0, 0x0341027e}, | ||
1081 | {0x0000b0e4, 0x035f0340}, | ||
1082 | {0x0000b0e8, 0x037f0360}, | ||
1083 | {0x0000b0ec, 0x04400441}, | ||
1084 | {0x0000b0f0, 0x0460045f}, | ||
1085 | {0x0000b0f4, 0x0541047f}, | ||
1086 | {0x0000b0f8, 0x055f0540}, | ||
1087 | {0x0000b0fc, 0x057f0560}, | ||
1088 | {0x0000b100, 0x06400641}, | ||
1089 | {0x0000b104, 0x0660065f}, | ||
1090 | {0x0000b108, 0x067e067f}, | ||
1091 | {0x0000b10c, 0x07410742}, | ||
1092 | {0x0000b110, 0x075f0740}, | ||
1093 | {0x0000b114, 0x077f0760}, | ||
1094 | {0x0000b118, 0x07800781}, | ||
1095 | {0x0000b11c, 0x07a0079f}, | ||
1096 | {0x0000b120, 0x07c107bf}, | ||
1097 | {0x0000b124, 0x000007c0}, | ||
1098 | {0x0000b128, 0x00000000}, | ||
1099 | {0x0000b12c, 0x00000000}, | ||
1100 | {0x0000b130, 0x00000000}, | ||
1101 | {0x0000b134, 0x00000000}, | ||
1102 | {0x0000b138, 0x00000000}, | ||
1103 | {0x0000b13c, 0x00000000}, | ||
1104 | {0x0000b140, 0x003f0020}, | ||
1105 | {0x0000b144, 0x00400041}, | ||
1106 | {0x0000b148, 0x0140005f}, | ||
1107 | {0x0000b14c, 0x0160015f}, | ||
1108 | {0x0000b150, 0x017e017f}, | ||
1109 | {0x0000b154, 0x02410242}, | ||
1110 | {0x0000b158, 0x025f0240}, | ||
1111 | {0x0000b15c, 0x027f0260}, | ||
1112 | {0x0000b160, 0x0341027e}, | ||
1113 | {0x0000b164, 0x035f0340}, | ||
1114 | {0x0000b168, 0x037f0360}, | ||
1115 | {0x0000b16c, 0x04400441}, | ||
1116 | {0x0000b170, 0x0460045f}, | ||
1117 | {0x0000b174, 0x0541047f}, | ||
1118 | {0x0000b178, 0x055f0540}, | ||
1119 | {0x0000b17c, 0x057f0560}, | ||
1120 | {0x0000b180, 0x06400641}, | ||
1121 | {0x0000b184, 0x0660065f}, | ||
1122 | {0x0000b188, 0x067e067f}, | ||
1123 | {0x0000b18c, 0x07410742}, | ||
1124 | {0x0000b190, 0x075f0740}, | ||
1125 | {0x0000b194, 0x077f0760}, | ||
1126 | {0x0000b198, 0x07800781}, | ||
1127 | {0x0000b19c, 0x07a0079f}, | ||
1128 | {0x0000b1a0, 0x07c107bf}, | ||
1129 | {0x0000b1a4, 0x000007c0}, | ||
1130 | {0x0000b1a8, 0x00000000}, | ||
1131 | {0x0000b1ac, 0x00000000}, | ||
1132 | {0x0000b1b0, 0x00000000}, | ||
1133 | {0x0000b1b4, 0x00000000}, | ||
1134 | {0x0000b1b8, 0x00000000}, | ||
1135 | {0x0000b1bc, 0x00000000}, | ||
1136 | {0x0000b1c0, 0x00000000}, | ||
1137 | {0x0000b1c4, 0x00000000}, | ||
1138 | {0x0000b1c8, 0x00000000}, | ||
1139 | {0x0000b1cc, 0x00000000}, | ||
1140 | {0x0000b1d0, 0x00000000}, | ||
1141 | {0x0000b1d4, 0x00000000}, | ||
1142 | {0x0000b1d8, 0x00000000}, | ||
1143 | {0x0000b1dc, 0x00000000}, | ||
1144 | {0x0000b1e0, 0x00000000}, | ||
1145 | {0x0000b1e4, 0x00000000}, | ||
1146 | {0x0000b1e8, 0x00000000}, | ||
1147 | {0x0000b1ec, 0x00000000}, | ||
1148 | {0x0000b1f0, 0x00000396}, | ||
1149 | {0x0000b1f4, 0x00000396}, | ||
1150 | {0x0000b1f8, 0x00000396}, | ||
1151 | {0x0000b1fc, 0x00000196}, | ||
1152 | }; | ||
1153 | |||
1154 | static const u32 ar955x_1p0_soc_preamble[][2] = { | ||
1155 | /* Addr allmodes */ | ||
1156 | {0x00007000, 0x00000000}, | ||
1157 | {0x00007004, 0x00000000}, | ||
1158 | {0x00007008, 0x00000000}, | ||
1159 | {0x0000700c, 0x00000000}, | ||
1160 | {0x0000701c, 0x00000000}, | ||
1161 | {0x00007020, 0x00000000}, | ||
1162 | {0x00007024, 0x00000000}, | ||
1163 | {0x00007028, 0x00000000}, | ||
1164 | {0x0000702c, 0x00000000}, | ||
1165 | {0x00007030, 0x00000000}, | ||
1166 | {0x00007034, 0x00000002}, | ||
1167 | {0x00007038, 0x000004c2}, | ||
1168 | {0x00007048, 0x00000000}, | ||
1169 | }; | ||
1170 | |||
1171 | static const u32 ar955x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { | ||
1172 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
1173 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
1174 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, | ||
1175 | }; | ||
1176 | |||
1177 | static const u32 ar955x_1p0_mac_postamble[][5] = { | ||
1178 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
1179 | {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, | ||
1180 | {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, | ||
1181 | {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, | ||
1182 | {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, | ||
1183 | {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, | ||
1184 | {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, | ||
1185 | {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, | ||
1186 | {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, | ||
1187 | }; | ||
1188 | |||
1189 | static const u32 ar955x_1p0_common_rx_gain_bounds[][5] = { | ||
1190 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
1191 | {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, | ||
1192 | {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, | ||
1193 | }; | ||
1194 | |||
1195 | static const u32 ar955x_1p0_modes_no_xpa_tx_gain_table[][9] = { | ||
1196 | /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ | ||
1197 | {0x0000a2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, | ||
1198 | {0x0000a2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, | ||
1199 | {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, | ||
1200 | {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, | ||
1201 | {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d7, 0x000050d7}, | ||
1202 | {0x0000a500, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, | ||
1203 | {0x0000a504, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, | ||
1204 | {0x0000a508, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, | ||
1205 | {0x0000a50c, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0b000006, 0x0b000006}, | ||
1206 | {0x0000a510, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x0f00000a, 0x0f00000a}, | ||
1207 | {0x0000a514, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x1300000c, 0x1300000c}, | ||
1208 | {0x0000a518, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1700000e, 0x1700000e}, | ||
1209 | {0x0000a51c, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x1b000012, 0x1b000012}, | ||
1210 | {0x0000a520, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x1f00004a, 0x1f00004a}, | ||
1211 | {0x0000a524, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x23000244, 0x23000244}, | ||
1212 | {0x0000a528, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2700022b, 0x2700022b}, | ||
1213 | {0x0000a52c, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x2b000625, 0x2b000625}, | ||
1214 | {0x0000a530, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x2f001006, 0x2f001006}, | ||
1215 | {0x0000a534, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x330008a0, 0x330008a0}, | ||
1216 | {0x0000a538, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x37000a2a, 0x37000a2a}, | ||
1217 | {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x3b001c23, 0x3b001c23}, | ||
1218 | {0x0000a540, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x3f0014a0, 0x3f0014a0}, | ||
1219 | {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x43001882, 0x43001882}, | ||
1220 | {0x0000a548, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x47001ca2, 0x47001ca2}, | ||
1221 | {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x4b001ec3, 0x4b001ec3}, | ||
1222 | {0x0000a550, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x4f00148c, 0x4f00148c}, | ||
1223 | {0x0000a554, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x53001c6e, 0x53001c6e}, | ||
1224 | {0x0000a558, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x57001c92, 0x57001c92}, | ||
1225 | {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x5c001af6, 0x5c001af6}, | ||
1226 | {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1227 | {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1228 | {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1229 | {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1230 | {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1231 | {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1232 | {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1233 | {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, | ||
1234 | {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
1235 | {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
1236 | {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
1237 | {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, | ||
1238 | {0x0000a610, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x04005001, 0x04005001}, | ||
1239 | {0x0000a614, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x03808e02, 0x03808e02}, | ||
1240 | {0x0000a618, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0300c000, 0x0300c000}, | ||
1241 | {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x03808e02, 0x03808e02}, | ||
1242 | {0x0000a620, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x03410c03, 0x03410c03}, | ||
1243 | {0x0000a624, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04014c03, 0x04014c03}, | ||
1244 | {0x0000a628, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x05818d04, 0x05818d04}, | ||
1245 | {0x0000a62c, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801cd04, 0x0801cd04}, | ||
1246 | {0x0000a630, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, | ||
1247 | {0x0000a634, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, | ||
1248 | {0x0000a638, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, | ||
1249 | {0x0000a63c, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, | ||
1250 | {0x0000b2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, | ||
1251 | {0x0000b2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, | ||
1252 | {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, | ||
1253 | {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, | ||
1254 | {0x0000c2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, | ||
1255 | {0x0000c2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, | ||
1256 | {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, | ||
1257 | {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, | ||
1258 | {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, | ||
1259 | {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | ||
1260 | {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, | ||
1261 | {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | ||
1262 | {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, | ||
1263 | {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, | ||
1264 | }; | ||
1265 | |||
1266 | static const u32 ar955x_1p0_soc_postamble[][5] = { | ||
1267 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | ||
1268 | {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, | ||
1269 | }; | ||
1270 | |||
1271 | static const u32 ar955x_1p0_modes_fast_clock[][3] = { | ||
1272 | /* Addr 5G_HT20 5G_HT40 */ | ||
1273 | {0x00001030, 0x00000268, 0x000004d0}, | ||
1274 | {0x00001070, 0x0000018c, 0x00000318}, | ||
1275 | {0x000010b0, 0x00000fd0, 0x00001fa0}, | ||
1276 | {0x00008014, 0x044c044c, 0x08980898}, | ||
1277 | {0x0000801c, 0x148ec02b, 0x148ec057}, | ||
1278 | {0x00008318, 0x000044c0, 0x00008980}, | ||
1279 | {0x00009e00, 0x0372131c, 0x0372131c}, | ||
1280 | {0x0000a230, 0x0000000b, 0x00000016}, | ||
1281 | {0x0000a254, 0x00000898, 0x00001130}, | ||
1282 | }; | ||
1283 | |||
1284 | #endif /* INITVALS_955X_1P0_H */ | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fe39eb4c42a1..79840d6deef2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -481,6 +481,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc); | |||
481 | void ath9k_btcoex_timer_pause(struct ath_softc *sc); | 481 | void ath9k_btcoex_timer_pause(struct ath_softc *sc); |
482 | void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); | 482 | void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); |
483 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); | 483 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); |
484 | void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); | ||
484 | #else | 485 | #else |
485 | static inline int ath9k_init_btcoex(struct ath_softc *sc) | 486 | static inline int ath9k_init_btcoex(struct ath_softc *sc) |
486 | { | 487 | { |
@@ -504,6 +505,9 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, | |||
504 | { | 505 | { |
505 | return 0; | 506 | return 0; |
506 | } | 507 | } |
508 | static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) | ||
509 | { | ||
510 | } | ||
507 | #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ | 511 | #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ |
508 | 512 | ||
509 | /********************/ | 513 | /********************/ |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 9ae6a4d97691..bacdb8fb4ef4 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -194,6 +194,14 @@ static void ath_btcoex_period_timer(unsigned long data) | |||
194 | struct ath_mci_profile *mci = &btcoex->mci; | 194 | struct ath_mci_profile *mci = &btcoex->mci; |
195 | u32 timer_period; | 195 | u32 timer_period; |
196 | bool is_btscan; | 196 | bool is_btscan; |
197 | unsigned long flags; | ||
198 | |||
199 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||
200 | if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { | ||
201 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
202 | goto skip_hw_wakeup; | ||
203 | } | ||
204 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
197 | 205 | ||
198 | ath9k_ps_wakeup(sc); | 206 | ath9k_ps_wakeup(sc); |
199 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) | 207 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) |
@@ -232,6 +240,7 @@ static void ath_btcoex_period_timer(unsigned long data) | |||
232 | } | 240 | } |
233 | 241 | ||
234 | ath9k_ps_restore(sc); | 242 | ath9k_ps_restore(sc); |
243 | skip_hw_wakeup: | ||
235 | timer_period = btcoex->btcoex_period; | 244 | timer_period = btcoex->btcoex_period; |
236 | mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); | 245 | mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); |
237 | } | 246 | } |
@@ -305,7 +314,8 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) | |||
305 | 314 | ||
306 | btcoex->bt_priority_cnt = 0; | 315 | btcoex->bt_priority_cnt = 0; |
307 | btcoex->bt_priority_time = jiffies; | 316 | btcoex->bt_priority_time = jiffies; |
308 | btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN); | 317 | clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); |
318 | clear_bit(BT_OP_SCAN, &btcoex->op_flags); | ||
309 | 319 | ||
310 | mod_timer(&btcoex->period_timer, jiffies); | 320 | mod_timer(&btcoex->period_timer, jiffies); |
311 | } | 321 | } |
@@ -327,6 +337,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) | |||
327 | btcoex->hw_timer_enabled = false; | 337 | btcoex->hw_timer_enabled = false; |
328 | } | 338 | } |
329 | 339 | ||
340 | void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) | ||
341 | { | ||
342 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
343 | |||
344 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | ||
345 | } | ||
346 | |||
330 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) | 347 | u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) |
331 | { | 348 | { |
332 | struct ath_btcoex *btcoex = &sc->btcoex; | 349 | struct ath_btcoex *btcoex = &sc->btcoex; |
@@ -376,9 +393,9 @@ void ath9k_stop_btcoex(struct ath_softc *sc) | |||
376 | 393 | ||
377 | if (ah->btcoex_hw.enabled && | 394 | if (ah->btcoex_hw.enabled && |
378 | ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { | 395 | ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { |
379 | ath9k_hw_btcoex_disable(ah); | ||
380 | if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) | 396 | if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) |
381 | ath9k_btcoex_timer_pause(sc); | 397 | ath9k_btcoex_timer_pause(sc); |
398 | ath9k_hw_btcoex_disable(ah); | ||
382 | if (AR_SREV_9462(ah)) | 399 | if (AR_SREV_9462(ah)) |
383 | ath_mci_flush_profile(&sc->btcoex.mci); | 400 | ath_mci_flush_profile(&sc->btcoex.mci); |
384 | } | 401 | } |
@@ -386,11 +403,13 @@ void ath9k_stop_btcoex(struct ath_softc *sc) | |||
386 | 403 | ||
387 | void ath9k_deinit_btcoex(struct ath_softc *sc) | 404 | void ath9k_deinit_btcoex(struct ath_softc *sc) |
388 | { | 405 | { |
406 | struct ath_hw *ah = sc->sc_ah; | ||
407 | |||
389 | if ((sc->btcoex.no_stomp_timer) && | 408 | if ((sc->btcoex.no_stomp_timer) && |
390 | ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) | 409 | ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) |
391 | ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); | 410 | ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); |
392 | 411 | ||
393 | if (AR_SREV_9462(sc->sc_ah)) | 412 | if (ath9k_hw_mci_is_enabled(ah)) |
394 | ath_mci_cleanup(sc); | 413 | ath_mci_cleanup(sc); |
395 | } | 414 | } |
396 | 415 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ebfb2a3c645c..c1659d079513 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -342,6 +342,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) | |||
342 | val = REG_READ(ah, AR_SREV); | 342 | val = REG_READ(ah, AR_SREV); |
343 | ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); | 343 | ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); |
344 | return; | 344 | return; |
345 | case AR9300_DEVID_QCA955X: | ||
346 | ah->hw_version.macVersion = AR_SREV_VERSION_9550; | ||
347 | return; | ||
345 | } | 348 | } |
346 | 349 | ||
347 | val = REG_READ(ah, AR_SREV) & AR_SREV_ID; | 350 | val = REG_READ(ah, AR_SREV) & AR_SREV_ID; |
@@ -646,6 +649,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) | |||
646 | case AR_SREV_VERSION_9485: | 649 | case AR_SREV_VERSION_9485: |
647 | case AR_SREV_VERSION_9340: | 650 | case AR_SREV_VERSION_9340: |
648 | case AR_SREV_VERSION_9462: | 651 | case AR_SREV_VERSION_9462: |
652 | case AR_SREV_VERSION_9550: | ||
649 | break; | 653 | break; |
650 | default: | 654 | default: |
651 | ath_err(common, | 655 | ath_err(common, |
@@ -655,7 +659,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) | |||
655 | } | 659 | } |
656 | 660 | ||
657 | if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) || | 661 | if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) || |
658 | AR_SREV_9330(ah)) | 662 | AR_SREV_9330(ah) || AR_SREV_9550(ah)) |
659 | ah->is_pciexpress = false; | 663 | ah->is_pciexpress = false; |
660 | 664 | ||
661 | ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); | 665 | ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); |
@@ -727,6 +731,7 @@ int ath9k_hw_init(struct ath_hw *ah) | |||
727 | case AR9300_DEVID_AR9485_PCIE: | 731 | case AR9300_DEVID_AR9485_PCIE: |
728 | case AR9300_DEVID_AR9330: | 732 | case AR9300_DEVID_AR9330: |
729 | case AR9300_DEVID_AR9340: | 733 | case AR9300_DEVID_AR9340: |
734 | case AR9300_DEVID_QCA955X: | ||
730 | case AR9300_DEVID_AR9580: | 735 | case AR9300_DEVID_AR9580: |
731 | case AR9300_DEVID_AR9462: | 736 | case AR9300_DEVID_AR9462: |
732 | break; | 737 | break; |
@@ -865,7 +870,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
865 | /* program BB PLL phase_shift */ | 870 | /* program BB PLL phase_shift */ |
866 | REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, | 871 | REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, |
867 | AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); | 872 | AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); |
868 | } else if (AR_SREV_9340(ah)) { | 873 | } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { |
869 | u32 regval, pll2_divint, pll2_divfrac, refdiv; | 874 | u32 regval, pll2_divint, pll2_divfrac, refdiv; |
870 | 875 | ||
871 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); | 876 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); |
@@ -879,9 +884,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
879 | pll2_divfrac = 0x1eb85; | 884 | pll2_divfrac = 0x1eb85; |
880 | refdiv = 3; | 885 | refdiv = 3; |
881 | } else { | 886 | } else { |
882 | pll2_divint = 88; | 887 | if (AR_SREV_9340(ah)) { |
883 | pll2_divfrac = 0; | 888 | pll2_divint = 88; |
884 | refdiv = 5; | 889 | pll2_divfrac = 0; |
890 | refdiv = 5; | ||
891 | } else { | ||
892 | pll2_divint = 0x11; | ||
893 | pll2_divfrac = 0x26666; | ||
894 | refdiv = 1; | ||
895 | } | ||
885 | } | 896 | } |
886 | 897 | ||
887 | regval = REG_READ(ah, AR_PHY_PLL_MODE); | 898 | regval = REG_READ(ah, AR_PHY_PLL_MODE); |
@@ -894,8 +905,12 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
894 | udelay(100); | 905 | udelay(100); |
895 | 906 | ||
896 | regval = REG_READ(ah, AR_PHY_PLL_MODE); | 907 | regval = REG_READ(ah, AR_PHY_PLL_MODE); |
897 | regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | | 908 | if (AR_SREV_9340(ah)) |
898 | (0x4 << 26) | (0x18 << 19); | 909 | regval = (regval & 0x80071fff) | (0x1 << 30) | |
910 | (0x1 << 13) | (0x4 << 26) | (0x18 << 19); | ||
911 | else | ||
912 | regval = (regval & 0x80071fff) | (0x3 << 30) | | ||
913 | (0x1 << 13) | (0x4 << 26) | (0x60 << 19); | ||
899 | REG_WRITE(ah, AR_PHY_PLL_MODE, regval); | 914 | REG_WRITE(ah, AR_PHY_PLL_MODE, regval); |
900 | REG_WRITE(ah, AR_PHY_PLL_MODE, | 915 | REG_WRITE(ah, AR_PHY_PLL_MODE, |
901 | REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); | 916 | REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); |
@@ -906,7 +921,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
906 | 921 | ||
907 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); | 922 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); |
908 | 923 | ||
909 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) | 924 | if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || |
925 | AR_SREV_9550(ah)) | ||
910 | udelay(1000); | 926 | udelay(1000); |
911 | 927 | ||
912 | /* Switch the core clock for ar9271 to 117Mhz */ | 928 | /* Switch the core clock for ar9271 to 117Mhz */ |
@@ -919,7 +935,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
919 | 935 | ||
920 | REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); | 936 | REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); |
921 | 937 | ||
922 | if (AR_SREV_9340(ah)) { | 938 | if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { |
923 | if (ah->is_clk_25mhz) { | 939 | if (ah->is_clk_25mhz) { |
924 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); | 940 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); |
925 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); | 941 | REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); |
@@ -943,7 +959,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, | |||
943 | AR_IMR_RXORN | | 959 | AR_IMR_RXORN | |
944 | AR_IMR_BCNMISC; | 960 | AR_IMR_BCNMISC; |
945 | 961 | ||
946 | if (AR_SREV_9340(ah)) | 962 | if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) |
947 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; | 963 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; |
948 | 964 | ||
949 | if (AR_SREV_9300_20_OR_LATER(ah)) { | 965 | if (AR_SREV_9300_20_OR_LATER(ah)) { |
@@ -1949,9 +1965,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1949 | if (!ath9k_hw_init_cal(ah, chan)) | 1965 | if (!ath9k_hw_init_cal(ah, chan)) |
1950 | return -EIO; | 1966 | return -EIO; |
1951 | 1967 | ||
1952 | ath9k_hw_loadnf(ah, chan); | ||
1953 | ath9k_hw_start_nfcal(ah, true); | ||
1954 | |||
1955 | if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata)) | 1968 | if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata)) |
1956 | return -EIO; | 1969 | return -EIO; |
1957 | 1970 | ||
@@ -1987,7 +2000,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1987 | REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); | 2000 | REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); |
1988 | } | 2001 | } |
1989 | #ifdef __BIG_ENDIAN | 2002 | #ifdef __BIG_ENDIAN |
1990 | else if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) | 2003 | else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || |
2004 | AR_SREV_9550(ah)) | ||
1991 | REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); | 2005 | REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); |
1992 | else | 2006 | else |
1993 | REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); | 2007 | REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); |
@@ -2000,6 +2014,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
2000 | if (ath9k_hw_mci_is_enabled(ah)) | 2014 | if (ath9k_hw_mci_is_enabled(ah)) |
2001 | ar9003_mci_check_bt(ah); | 2015 | ar9003_mci_check_bt(ah); |
2002 | 2016 | ||
2017 | ath9k_hw_loadnf(ah, chan); | ||
2018 | ath9k_hw_start_nfcal(ah, true); | ||
2019 | |||
2003 | if (AR_SREV_9300_20_OR_LATER(ah)) { | 2020 | if (AR_SREV_9300_20_OR_LATER(ah)) { |
2004 | ar9003_hw_bb_watchdog_config(ah); | 2021 | ar9003_hw_bb_watchdog_config(ah); |
2005 | 2022 | ||
@@ -3137,6 +3154,7 @@ static struct { | |||
3137 | { AR_SREV_VERSION_9340, "9340" }, | 3154 | { AR_SREV_VERSION_9340, "9340" }, |
3138 | { AR_SREV_VERSION_9485, "9485" }, | 3155 | { AR_SREV_VERSION_9485, "9485" }, |
3139 | { AR_SREV_VERSION_9462, "9462" }, | 3156 | { AR_SREV_VERSION_9462, "9462" }, |
3157 | { AR_SREV_VERSION_9550, "9550" }, | ||
3140 | }; | 3158 | }; |
3141 | 3159 | ||
3142 | /* For devices with external radios */ | 3160 | /* For devices with external radios */ |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 94096607cbdd..26da1732978d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -48,6 +48,7 @@ | |||
48 | #define AR9300_DEVID_AR9580 0x0033 | 48 | #define AR9300_DEVID_AR9580 0x0033 |
49 | #define AR9300_DEVID_AR9462 0x0034 | 49 | #define AR9300_DEVID_AR9462 0x0034 |
50 | #define AR9300_DEVID_AR9330 0x0035 | 50 | #define AR9300_DEVID_AR9330 0x0035 |
51 | #define AR9300_DEVID_QCA955X 0x0038 | ||
51 | 52 | ||
52 | #define AR5416_AR9100_DEVID 0x000b | 53 | #define AR5416_AR9100_DEVID 0x000b |
53 | 54 | ||
@@ -818,6 +819,7 @@ struct ath_hw { | |||
818 | struct ar5416IniArray iniModesFastClock; | 819 | struct ar5416IniArray iniModesFastClock; |
819 | struct ar5416IniArray iniAdditional; | 820 | struct ar5416IniArray iniAdditional; |
820 | struct ar5416IniArray iniModesRxGain; | 821 | struct ar5416IniArray iniModesRxGain; |
822 | struct ar5416IniArray ini_modes_rx_gain_bounds; | ||
821 | struct ar5416IniArray iniModesTxGain; | 823 | struct ar5416IniArray iniModesTxGain; |
822 | struct ar5416IniArray iniCckfirNormal; | 824 | struct ar5416IniArray iniCckfirNormal; |
823 | struct ar5416IniArray iniCckfirJapan2484; | 825 | struct ar5416IniArray iniCckfirJapan2484; |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 04ef775ccee1..7990cd55599c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -810,7 +810,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) | |||
810 | return; | 810 | return; |
811 | } | 811 | } |
812 | 812 | ||
813 | if (AR_SREV_9340(ah)) | 813 | if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) |
814 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; | 814 | sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; |
815 | 815 | ||
816 | async_mask = AR_INTR_MAC_IRQ; | 816 | async_mask = AR_INTR_MAC_IRQ; |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 21c955609e6c..0eba36dca6f8 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -646,6 +646,7 @@ enum ath9k_rx_filter { | |||
646 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, | 646 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, |
647 | ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, | 647 | ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, |
648 | ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000, | 648 | ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000, |
649 | ATH9K_RX_FILTER_4ADDRESS = 0x00100000, | ||
649 | }; | 650 | }; |
650 | 651 | ||
651 | #define ATH9K_RATESERIES_RTS_CTS 0x0001 | 652 | #define ATH9K_RATESERIES_RTS_CTS 0x0001 |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e4e73f061a22..248e5b24acfa 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -130,6 +130,8 @@ void ath9k_ps_restore(struct ath_softc *sc) | |||
130 | PS_WAIT_FOR_PSPOLL_DATA | | 130 | PS_WAIT_FOR_PSPOLL_DATA | |
131 | PS_WAIT_FOR_TX_ACK))) { | 131 | PS_WAIT_FOR_TX_ACK))) { |
132 | mode = ATH9K_PM_NETWORK_SLEEP; | 132 | mode = ATH9K_PM_NETWORK_SLEEP; |
133 | if (ath9k_hw_btcoex_is_enabled(sc->sc_ah)) | ||
134 | ath9k_btcoex_stop_gen_timer(sc); | ||
133 | } else { | 135 | } else { |
134 | goto unlock; | 136 | goto unlock; |
135 | } | 137 | } |
@@ -169,7 +171,8 @@ static void ath_restart_work(struct ath_softc *sc) | |||
169 | 171 | ||
170 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 172 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
171 | 173 | ||
172 | if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah)) | 174 | if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || |
175 | AR_SREV_9550(sc->sc_ah)) | ||
173 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, | 176 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, |
174 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); | 177 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); |
175 | 178 | ||
@@ -666,8 +669,6 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
666 | 669 | ||
667 | spin_unlock_bh(&sc->sc_pcu_lock); | 670 | spin_unlock_bh(&sc->sc_pcu_lock); |
668 | 671 | ||
669 | ath9k_start_btcoex(sc); | ||
670 | |||
671 | if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) | 672 | if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) |
672 | common->bus_ops->extn_synch_en(common); | 673 | common->bus_ops->extn_synch_en(common); |
673 | 674 | ||
@@ -774,8 +775,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
774 | /* Ensure HW is awake when we try to shut it down. */ | 775 | /* Ensure HW is awake when we try to shut it down. */ |
775 | ath9k_ps_wakeup(sc); | 776 | ath9k_ps_wakeup(sc); |
776 | 777 | ||
777 | ath9k_stop_btcoex(sc); | ||
778 | |||
779 | spin_lock_bh(&sc->sc_pcu_lock); | 778 | spin_lock_bh(&sc->sc_pcu_lock); |
780 | 779 | ||
781 | /* prevent tasklets to enable interrupts once we disable them */ | 780 | /* prevent tasklets to enable interrupts once we disable them */ |
@@ -1139,14 +1138,17 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
1139 | 1138 | ||
1140 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | 1139 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
1141 | sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); | 1140 | sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
1142 | if (sc->ps_idle) | 1141 | if (sc->ps_idle) { |
1143 | ath_cancel_work(sc); | 1142 | ath_cancel_work(sc); |
1144 | else | 1143 | ath9k_stop_btcoex(sc); |
1144 | } else { | ||
1145 | ath9k_start_btcoex(sc); | ||
1145 | /* | 1146 | /* |
1146 | * The chip needs a reset to properly wake up from | 1147 | * The chip needs a reset to properly wake up from |
1147 | * full sleep | 1148 | * full sleep |
1148 | */ | 1149 | */ |
1149 | reset_channel = ah->chip_fullsleep; | 1150 | reset_channel = ah->chip_fullsleep; |
1151 | } | ||
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | /* | 1154 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 64cc782587d8..87acff7fdaae 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c | |||
@@ -174,8 +174,8 @@ skip_tuning: | |||
174 | btcoex->btcoex_period >>= 1; | 174 | btcoex->btcoex_period >>= 1; |
175 | } | 175 | } |
176 | 176 | ||
177 | ath9k_hw_btcoex_disable(sc->sc_ah); | ||
178 | ath9k_btcoex_timer_pause(sc); | 177 | ath9k_btcoex_timer_pause(sc); |
178 | ath9k_hw_btcoex_disable(sc->sc_ah); | ||
179 | 179 | ||
180 | if (IS_CHAN_5GHZ(sc->sc_ah->curchan)) | 180 | if (IS_CHAN_5GHZ(sc->sc_ah->curchan)) |
181 | return; | 181 | return; |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6a7dd26f2a13..11f3703a420a 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -430,6 +430,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | |||
430 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; | 430 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; |
431 | } | 431 | } |
432 | 432 | ||
433 | if (AR_SREV_9550(sc->sc_ah)) | ||
434 | rfilt |= ATH9K_RX_FILTER_4ADDRESS; | ||
435 | |||
433 | return rfilt; | 436 | return rfilt; |
434 | 437 | ||
435 | } | 438 | } |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5046b282a93c..6592c07ac646 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -798,6 +798,7 @@ | |||
798 | #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ | 798 | #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ |
799 | #define AR_SREV_VERSION_9462 0x280 | 799 | #define AR_SREV_VERSION_9462 0x280 |
800 | #define AR_SREV_REVISION_9462_20 2 | 800 | #define AR_SREV_REVISION_9462_20 2 |
801 | #define AR_SREV_VERSION_9550 0x400 | ||
801 | 802 | ||
802 | #define AR_SREV_5416(_ah) \ | 803 | #define AR_SREV_5416(_ah) \ |
803 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ | 804 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ |
@@ -905,6 +906,9 @@ | |||
905 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ | 906 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ |
906 | ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) | 907 | ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) |
907 | 908 | ||
909 | #define AR_SREV_9550(_ah) \ | ||
910 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) | ||
911 | |||
908 | #define AR_SREV_9580(_ah) \ | 912 | #define AR_SREV_9580(_ah) \ |
909 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ | 913 | (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ |
910 | ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) | 914 | ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) |
@@ -1643,11 +1647,11 @@ enum { | |||
1643 | 1647 | ||
1644 | #define AR_TPC 0x80e8 | 1648 | #define AR_TPC 0x80e8 |
1645 | #define AR_TPC_ACK 0x0000003f | 1649 | #define AR_TPC_ACK 0x0000003f |
1646 | #define AR_TPC_ACK_S 0x00 | 1650 | #define AR_TPC_ACK_S 0 |
1647 | #define AR_TPC_CTS 0x00003f00 | 1651 | #define AR_TPC_CTS 0x00003f00 |
1648 | #define AR_TPC_CTS_S 0x08 | 1652 | #define AR_TPC_CTS_S 8 |
1649 | #define AR_TPC_CHIRP 0x003f0000 | 1653 | #define AR_TPC_CHIRP 0x003f0000 |
1650 | #define AR_TPC_CHIRP_S 0x16 | 1654 | #define AR_TPC_CHIRP_S 16 |
1651 | 1655 | ||
1652 | #define AR_QUIET1 0x80fc | 1656 | #define AR_QUIET1 0x80fc |
1653 | #define AR_QUIET1_NEXT_QUIET_S 0 | 1657 | #define AR_QUIET1_NEXT_QUIET_S 0 |
@@ -2077,12 +2081,6 @@ enum { | |||
2077 | AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ | 2081 | AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ |
2078 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ | 2082 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ |
2079 | AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ | 2083 | AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ |
2080 | AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ | ||
2081 | AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ | ||
2082 | AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ | ||
2083 | AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ | ||
2084 | AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ | ||
2085 | AR_MCI_INTERRUPT_RX_MSG_CONT_RST | \ | ||
2086 | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) | 2084 | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) |
2087 | 2085 | ||
2088 | #define AR_MCI_CPU_INT 0x1840 | 2086 | #define AR_MCI_CPU_INT 0x1840 |
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 0cea20e3e250..376be11161c0 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h | |||
@@ -289,6 +289,7 @@ struct ar9170 { | |||
289 | unsigned int mem_block_size; | 289 | unsigned int mem_block_size; |
290 | unsigned int rx_size; | 290 | unsigned int rx_size; |
291 | unsigned int tx_seq_table; | 291 | unsigned int tx_seq_table; |
292 | bool ba_filter; | ||
292 | } fw; | 293 | } fw; |
293 | 294 | ||
294 | /* interface configuration combinations */ | 295 | /* interface configuration combinations */ |
@@ -425,6 +426,10 @@ struct ar9170 { | |||
425 | struct sk_buff *rx_failover; | 426 | struct sk_buff *rx_failover; |
426 | int rx_failover_missing; | 427 | int rx_failover_missing; |
427 | 428 | ||
429 | /* FIFO for collecting outstanding BlockAckRequest */ | ||
430 | struct list_head bar_list[__AR9170_NUM_TXQ]; | ||
431 | spinlock_t bar_list_lock[__AR9170_NUM_TXQ]; | ||
432 | |||
428 | #ifdef CONFIG_CARL9170_WPC | 433 | #ifdef CONFIG_CARL9170_WPC |
429 | struct { | 434 | struct { |
430 | bool pbc_state; | 435 | bool pbc_state; |
@@ -468,6 +473,12 @@ enum carl9170_ps_off_override_reasons { | |||
468 | PS_OFF_BCN = BIT(1), | 473 | PS_OFF_BCN = BIT(1), |
469 | }; | 474 | }; |
470 | 475 | ||
476 | struct carl9170_bar_list_entry { | ||
477 | struct list_head list; | ||
478 | struct rcu_head head; | ||
479 | struct sk_buff *skb; | ||
480 | }; | ||
481 | |||
471 | struct carl9170_ba_stats { | 482 | struct carl9170_ba_stats { |
472 | u8 ampdu_len; | 483 | u8 ampdu_len; |
473 | u8 ampdu_ack_len; | 484 | u8 ampdu_ack_len; |
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 5c73c03872f3..c5ca6f1f5836 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c | |||
@@ -307,6 +307,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) | |||
307 | if (SUPP(CARL9170FW_WOL)) | 307 | if (SUPP(CARL9170FW_WOL)) |
308 | device_set_wakeup_enable(&ar->udev->dev, true); | 308 | device_set_wakeup_enable(&ar->udev->dev, true); |
309 | 309 | ||
310 | if (SUPP(CARL9170FW_RX_BA_FILTER)) | ||
311 | ar->fw.ba_filter = true; | ||
312 | |||
310 | if_comb_types = BIT(NL80211_IFTYPE_STATION) | | 313 | if_comb_types = BIT(NL80211_IFTYPE_STATION) | |
311 | BIT(NL80211_IFTYPE_P2P_CLIENT); | 314 | BIT(NL80211_IFTYPE_P2P_CLIENT); |
312 | 315 | ||
diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 6d9c0891ce7f..66848d47c88e 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h | |||
@@ -78,6 +78,9 @@ enum carl9170fw_feature_list { | |||
78 | /* HW (ANI, CCA, MIB) tally counters */ | 78 | /* HW (ANI, CCA, MIB) tally counters */ |
79 | CARL9170FW_HW_COUNTERS, | 79 | CARL9170FW_HW_COUNTERS, |
80 | 80 | ||
81 | /* Firmware will pass BA when BARs are queued */ | ||
82 | CARL9170FW_RX_BA_FILTER, | ||
83 | |||
81 | /* KEEP LAST */ | 84 | /* KEEP LAST */ |
82 | __CARL9170FW_FEATURE_NUM | 85 | __CARL9170FW_FEATURE_NUM |
83 | }; | 86 | }; |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8d2523b3f722..858e58dfc4dc 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
@@ -949,6 +949,9 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, | |||
949 | if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) { | 949 | if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) { |
950 | u32 rx_filter = 0; | 950 | u32 rx_filter = 0; |
951 | 951 | ||
952 | if (!ar->fw.ba_filter) | ||
953 | rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; | ||
954 | |||
952 | if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))) | 955 | if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))) |
953 | rx_filter |= CARL9170_RX_FILTER_BAD; | 956 | rx_filter |= CARL9170_RX_FILTER_BAD; |
954 | 957 | ||
@@ -1753,6 +1756,9 @@ void *carl9170_alloc(size_t priv_size) | |||
1753 | for (i = 0; i < ar->hw->queues; i++) { | 1756 | for (i = 0; i < ar->hw->queues; i++) { |
1754 | skb_queue_head_init(&ar->tx_status[i]); | 1757 | skb_queue_head_init(&ar->tx_status[i]); |
1755 | skb_queue_head_init(&ar->tx_pending[i]); | 1758 | skb_queue_head_init(&ar->tx_pending[i]); |
1759 | |||
1760 | INIT_LIST_HEAD(&ar->bar_list[i]); | ||
1761 | spin_lock_init(&ar->bar_list_lock[i]); | ||
1756 | } | 1762 | } |
1757 | INIT_WORK(&ar->ps_work, carl9170_ps_work); | 1763 | INIT_WORK(&ar->ps_work, carl9170_ps_work); |
1758 | INIT_WORK(&ar->ping_work, carl9170_ping_work); | 1764 | INIT_WORK(&ar->ping_work, carl9170_ping_work); |
diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 7a8e90eaad83..6f6a34155667 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c | |||
@@ -576,6 +576,53 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) | |||
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) | ||
580 | { | ||
581 | struct ieee80211_bar *bar = (void *) data; | ||
582 | struct carl9170_bar_list_entry *entry; | ||
583 | unsigned int queue; | ||
584 | |||
585 | if (likely(!ieee80211_is_back(bar->frame_control))) | ||
586 | return; | ||
587 | |||
588 | if (len <= sizeof(*bar) + FCS_LEN) | ||
589 | return; | ||
590 | |||
591 | queue = TID_TO_WME_AC(((le16_to_cpu(bar->control) & | ||
592 | IEEE80211_BAR_CTRL_TID_INFO_MASK) >> | ||
593 | IEEE80211_BAR_CTRL_TID_INFO_SHIFT) & 7); | ||
594 | |||
595 | rcu_read_lock(); | ||
596 | list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) { | ||
597 | struct sk_buff *entry_skb = entry->skb; | ||
598 | struct _carl9170_tx_superframe *super = (void *)entry_skb->data; | ||
599 | struct ieee80211_bar *entry_bar = (void *)super->frame_data; | ||
600 | |||
601 | #define TID_CHECK(a, b) ( \ | ||
602 | ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \ | ||
603 | ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \ | ||
604 | |||
605 | if (bar->start_seq_num == entry_bar->start_seq_num && | ||
606 | TID_CHECK(bar->control, entry_bar->control) && | ||
607 | compare_ether_addr(bar->ra, entry_bar->ta) == 0 && | ||
608 | compare_ether_addr(bar->ta, entry_bar->ra) == 0) { | ||
609 | struct ieee80211_tx_info *tx_info; | ||
610 | |||
611 | tx_info = IEEE80211_SKB_CB(entry_skb); | ||
612 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | ||
613 | |||
614 | spin_lock_bh(&ar->bar_list_lock[queue]); | ||
615 | list_del_rcu(&entry->list); | ||
616 | spin_unlock_bh(&ar->bar_list_lock[queue]); | ||
617 | kfree_rcu(entry, head); | ||
618 | break; | ||
619 | } | ||
620 | } | ||
621 | rcu_read_unlock(); | ||
622 | |||
623 | #undef TID_CHECK | ||
624 | } | ||
625 | |||
579 | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) | 626 | static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) |
580 | { | 627 | { |
581 | __le16 fc; | 628 | __le16 fc; |
@@ -738,6 +785,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | |||
738 | 785 | ||
739 | carl9170_ps_beacon(ar, buf, mpdu_len); | 786 | carl9170_ps_beacon(ar, buf, mpdu_len); |
740 | 787 | ||
788 | carl9170_ba_check(ar, buf, mpdu_len); | ||
789 | |||
741 | skb = carl9170_rx_copy_data(buf, mpdu_len); | 790 | skb = carl9170_rx_copy_data(buf, mpdu_len); |
742 | if (!skb) | 791 | if (!skb) |
743 | goto drop; | 792 | goto drop; |
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index aed305177af6..6a8681407a1d 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c | |||
@@ -277,11 +277,11 @@ static void carl9170_tx_release(struct kref *ref) | |||
277 | return; | 277 | return; |
278 | 278 | ||
279 | BUILD_BUG_ON( | 279 | BUILD_BUG_ON( |
280 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); | 280 | offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); |
281 | 281 | ||
282 | memset(&txinfo->status.ampdu_ack_len, 0, | 282 | memset(&txinfo->status.ack_signal, 0, |
283 | sizeof(struct ieee80211_tx_info) - | 283 | sizeof(struct ieee80211_tx_info) - |
284 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); | 284 | offsetof(struct ieee80211_tx_info, status.ack_signal)); |
285 | 285 | ||
286 | if (atomic_read(&ar->tx_total_queued)) | 286 | if (atomic_read(&ar->tx_total_queued)) |
287 | ar->tx_schedule = true; | 287 | ar->tx_schedule = true; |
@@ -436,6 +436,45 @@ out_rcu: | |||
436 | rcu_read_unlock(); | 436 | rcu_read_unlock(); |
437 | } | 437 | } |
438 | 438 | ||
439 | static void carl9170_tx_bar_status(struct ar9170 *ar, struct sk_buff *skb, | ||
440 | struct ieee80211_tx_info *tx_info) | ||
441 | { | ||
442 | struct _carl9170_tx_superframe *super = (void *) skb->data; | ||
443 | struct ieee80211_bar *bar = (void *) super->frame_data; | ||
444 | |||
445 | /* | ||
446 | * Unlike all other frames, the status report for BARs does | ||
447 | * not directly come from the hardware as it is incapable of | ||
448 | * matching a BA to a previously send BAR. | ||
449 | * Instead the RX-path will scan for incoming BAs and set the | ||
450 | * IEEE80211_TX_STAT_ACK if it sees one that was likely | ||
451 | * caused by a BAR from us. | ||
452 | */ | ||
453 | |||
454 | if (unlikely(ieee80211_is_back_req(bar->frame_control)) && | ||
455 | !(tx_info->flags & IEEE80211_TX_STAT_ACK)) { | ||
456 | struct carl9170_bar_list_entry *entry; | ||
457 | int queue = skb_get_queue_mapping(skb); | ||
458 | |||
459 | rcu_read_lock(); | ||
460 | list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) { | ||
461 | if (entry->skb == skb) { | ||
462 | spin_lock_bh(&ar->bar_list_lock[queue]); | ||
463 | list_del_rcu(&entry->list); | ||
464 | spin_unlock_bh(&ar->bar_list_lock[queue]); | ||
465 | kfree_rcu(entry, head); | ||
466 | goto out; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | WARN(1, "bar not found in %d - ra:%pM ta:%pM c:%x ssn:%x\n", | ||
471 | queue, bar->ra, bar->ta, bar->control, | ||
472 | bar->start_seq_num); | ||
473 | out: | ||
474 | rcu_read_unlock(); | ||
475 | } | ||
476 | } | ||
477 | |||
439 | void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, | 478 | void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, |
440 | const bool success) | 479 | const bool success) |
441 | { | 480 | { |
@@ -445,6 +484,8 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, | |||
445 | 484 | ||
446 | txinfo = IEEE80211_SKB_CB(skb); | 485 | txinfo = IEEE80211_SKB_CB(skb); |
447 | 486 | ||
487 | carl9170_tx_bar_status(ar, skb, txinfo); | ||
488 | |||
448 | if (success) | 489 | if (success) |
449 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | 490 | txinfo->flags |= IEEE80211_TX_STAT_ACK; |
450 | else | 491 | else |
@@ -1265,6 +1306,26 @@ out_rcu: | |||
1265 | return false; | 1306 | return false; |
1266 | } | 1307 | } |
1267 | 1308 | ||
1309 | static void carl9170_bar_check(struct ar9170 *ar, struct sk_buff *skb) | ||
1310 | { | ||
1311 | struct _carl9170_tx_superframe *super = (void *) skb->data; | ||
1312 | struct ieee80211_bar *bar = (void *) super->frame_data; | ||
1313 | |||
1314 | if (unlikely(ieee80211_is_back_req(bar->frame_control)) && | ||
1315 | skb->len >= sizeof(struct ieee80211_bar)) { | ||
1316 | struct carl9170_bar_list_entry *entry; | ||
1317 | unsigned int queue = skb_get_queue_mapping(skb); | ||
1318 | |||
1319 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
1320 | if (!WARN_ON_ONCE(!entry)) { | ||
1321 | entry->skb = skb; | ||
1322 | spin_lock_bh(&ar->bar_list_lock[queue]); | ||
1323 | list_add_tail_rcu(&entry->list, &ar->bar_list[queue]); | ||
1324 | spin_unlock_bh(&ar->bar_list_lock[queue]); | ||
1325 | } | ||
1326 | } | ||
1327 | } | ||
1328 | |||
1268 | static void carl9170_tx(struct ar9170 *ar) | 1329 | static void carl9170_tx(struct ar9170 *ar) |
1269 | { | 1330 | { |
1270 | struct sk_buff *skb; | 1331 | struct sk_buff *skb; |
@@ -1287,6 +1348,8 @@ static void carl9170_tx(struct ar9170 *ar) | |||
1287 | if (unlikely(carl9170_tx_ps_drop(ar, skb))) | 1348 | if (unlikely(carl9170_tx_ps_drop(ar, skb))) |
1288 | continue; | 1349 | continue; |
1289 | 1350 | ||
1351 | carl9170_bar_check(ar, skb); | ||
1352 | |||
1290 | atomic_inc(&ar->tx_total_pending); | 1353 | atomic_inc(&ar->tx_total_pending); |
1291 | 1354 | ||
1292 | q = __carl9170_get_queue(ar, i); | 1355 | q = __carl9170_get_queue(ar, i); |
diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index e651db856344..2ec3e9191e4d 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __CARL9170_SHARED_VERSION_H | 1 | #ifndef __CARL9170_SHARED_VERSION_H |
2 | #define __CARL9170_SHARED_VERSION_H | 2 | #define __CARL9170_SHARED_VERSION_H |
3 | #define CARL9170FW_VERSION_YEAR 11 | 3 | #define CARL9170FW_VERSION_YEAR 12 |
4 | #define CARL9170FW_VERSION_MONTH 8 | 4 | #define CARL9170FW_VERSION_MONTH 7 |
5 | #define CARL9170FW_VERSION_DAY 15 | 5 | #define CARL9170FW_VERSION_DAY 7 |
6 | #define CARL9170FW_VERSION_GIT "1.9.4" | 6 | #define CARL9170FW_VERSION_GIT "1.9.6" |
7 | #endif /* __CARL9170_SHARED_VERSION_H */ | 7 | #endif /* __CARL9170_SHARED_VERSION_H */ |
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 108118820b36..b92bb9c92ad1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c | |||
@@ -1369,7 +1369,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) | |||
1369 | i << 2); | 1369 | i << 2); |
1370 | b43_nphy_poll_rssi(dev, 2, results[i], 8); | 1370 | b43_nphy_poll_rssi(dev, 2, results[i], 8); |
1371 | } | 1371 | } |
1372 | for (i = 0; i < 4; i++) { | 1372 | for (i = 0; i < 4; i += 2) { |
1373 | s32 curr; | 1373 | s32 curr; |
1374 | s32 mind = 40; | 1374 | s32 mind = 40; |
1375 | s32 minpoll = 249; | 1375 | s32 minpoll = 249; |
@@ -1415,14 +1415,15 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) | |||
1415 | b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 1, i); | 1415 | b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 1, i); |
1416 | b43_nphy_poll_rssi(dev, i, poll_results, 8); | 1416 | b43_nphy_poll_rssi(dev, i, poll_results, 8); |
1417 | for (j = 0; j < 4; j++) { | 1417 | for (j = 0; j < 4; j++) { |
1418 | if (j / 2 == core) | 1418 | if (j / 2 == core) { |
1419 | offset[j] = 232 - poll_results[j]; | 1419 | offset[j] = 232 - poll_results[j]; |
1420 | if (offset[j] < 0) | 1420 | if (offset[j] < 0) |
1421 | offset[j] = -(abs(offset[j] + 4) / 8); | 1421 | offset[j] = -(abs(offset[j] + 4) / 8); |
1422 | else | 1422 | else |
1423 | offset[j] = (offset[j] + 4) / 8; | 1423 | offset[j] = (offset[j] + 4) / 8; |
1424 | b43_nphy_scale_offset_rssi(dev, 0, | 1424 | b43_nphy_scale_offset_rssi(dev, 0, |
1425 | offset[2 * core], core + 1, j % 2, i); | 1425 | offset[2 * core], core + 1, j % 2, i); |
1426 | } | ||
1426 | } | 1427 | } |
1427 | } | 1428 | } |
1428 | } | 1429 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index 3c6f9b1e8d05..8c9345dd37d2 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c | |||
@@ -318,10 +318,6 @@ | |||
318 | #define IS_SIM(chippkg) \ | 318 | #define IS_SIM(chippkg) \ |
319 | ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) | 319 | ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) |
320 | 320 | ||
321 | #define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID) | ||
322 | |||
323 | #define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID)) | ||
324 | |||
325 | #ifdef DEBUG | 321 | #ifdef DEBUG |
326 | #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) | 322 | #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) |
327 | #else | 323 | #else |
@@ -473,9 +469,6 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) | |||
473 | sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; | 469 | sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; |
474 | } | 470 | } |
475 | 471 | ||
476 | /* figure out buscore */ | ||
477 | sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0); | ||
478 | |||
479 | return true; | 472 | return true; |
480 | } | 473 | } |
481 | 474 | ||
@@ -483,11 +476,7 @@ static struct si_info *ai_doattach(struct si_info *sii, | |||
483 | struct bcma_bus *pbus) | 476 | struct bcma_bus *pbus) |
484 | { | 477 | { |
485 | struct si_pub *sih = &sii->pub; | 478 | struct si_pub *sih = &sii->pub; |
486 | u32 w, savewin; | ||
487 | struct bcma_device *cc; | 479 | struct bcma_device *cc; |
488 | struct ssb_sprom *sprom = &pbus->sprom; | ||
489 | |||
490 | savewin = 0; | ||
491 | 480 | ||
492 | sii->icbus = pbus; | 481 | sii->icbus = pbus; |
493 | sii->pcibus = pbus->host_pci; | 482 | sii->pcibus = pbus->host_pci; |
@@ -510,47 +499,7 @@ static struct si_info *ai_doattach(struct si_info *sii, | |||
510 | 499 | ||
511 | /* PMU specific initializations */ | 500 | /* PMU specific initializations */ |
512 | if (ai_get_cccaps(sih) & CC_CAP_PMU) { | 501 | if (ai_get_cccaps(sih) & CC_CAP_PMU) { |
513 | si_pmu_init(sih); | ||
514 | (void)si_pmu_measure_alpclk(sih); | 502 | (void)si_pmu_measure_alpclk(sih); |
515 | si_pmu_res_init(sih); | ||
516 | } | ||
517 | |||
518 | /* setup the GPIO based LED powersave register */ | ||
519 | w = (sprom->leddc_on_time << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | | ||
520 | (sprom->leddc_off_time << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT); | ||
521 | if (w == 0) | ||
522 | w = DEFAULT_GPIOTIMERVAL; | ||
523 | ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval), | ||
524 | ~0, w); | ||
525 | |||
526 | if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) { | ||
527 | /* | ||
528 | * enable 12 mA drive strenth for 43224 and | ||
529 | * set chipControl register bit 15 | ||
530 | */ | ||
531 | if (ai_get_chiprev(sih) == 0) { | ||
532 | SI_MSG("Applying 43224A0 WARs\n"); | ||
533 | ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol), | ||
534 | CCTRL43224_GPIO_TOGGLE, | ||
535 | CCTRL43224_GPIO_TOGGLE); | ||
536 | si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, | ||
537 | CCTRL_43224A0_12MA_LED_DRIVE); | ||
538 | } | ||
539 | if (ai_get_chiprev(sih) >= 1) { | ||
540 | SI_MSG("Applying 43224B0+ WARs\n"); | ||
541 | si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, | ||
542 | CCTRL_43224B0_12MA_LED_DRIVE); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | if (ai_get_chip_id(sih) == BCM4313_CHIP_ID) { | ||
547 | /* | ||
548 | * enable 12 mA drive strenth for 4313 and | ||
549 | * set chipControl register bit 1 | ||
550 | */ | ||
551 | SI_MSG("Applying 4313 WARs\n"); | ||
552 | si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, | ||
553 | CCTRL_4313_12MA_LED_DRIVE); | ||
554 | } | 503 | } |
555 | 504 | ||
556 | return sii; | 505 | return sii; |
@@ -589,7 +538,7 @@ void ai_detach(struct si_pub *sih) | |||
589 | struct si_pub *si_local = NULL; | 538 | struct si_pub *si_local = NULL; |
590 | memcpy(&si_local, &sih, sizeof(struct si_pub **)); | 539 | memcpy(&si_local, &sih, sizeof(struct si_pub **)); |
591 | 540 | ||
592 | sii = (struct si_info *)sih; | 541 | sii = container_of(sih, struct si_info, pub); |
593 | 542 | ||
594 | if (sii == NULL) | 543 | if (sii == NULL) |
595 | return; | 544 | return; |
@@ -597,27 +546,6 @@ void ai_detach(struct si_pub *sih) | |||
597 | kfree(sii); | 546 | kfree(sii); |
598 | } | 547 | } |
599 | 548 | ||
600 | /* return index of coreid or BADIDX if not found */ | ||
601 | struct bcma_device *ai_findcore(struct si_pub *sih, u16 coreid, u16 coreunit) | ||
602 | { | ||
603 | struct bcma_device *core; | ||
604 | struct si_info *sii; | ||
605 | uint found; | ||
606 | |||
607 | sii = (struct si_info *)sih; | ||
608 | |||
609 | found = 0; | ||
610 | |||
611 | list_for_each_entry(core, &sii->icbus->cores, list) | ||
612 | if (core->id.id == coreid) { | ||
613 | if (found == coreunit) | ||
614 | return core; | ||
615 | found++; | ||
616 | } | ||
617 | |||
618 | return NULL; | ||
619 | } | ||
620 | |||
621 | /* | 549 | /* |
622 | * read/modify chipcommon core register. | 550 | * read/modify chipcommon core register. |
623 | */ | 551 | */ |
@@ -627,7 +555,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val) | |||
627 | u32 w; | 555 | u32 w; |
628 | struct si_info *sii; | 556 | struct si_info *sii; |
629 | 557 | ||
630 | sii = (struct si_info *)sih; | 558 | sii = container_of(sih, struct si_info, pub); |
631 | cc = sii->icbus->drv_cc.core; | 559 | cc = sii->icbus->drv_cc.core; |
632 | 560 | ||
633 | /* mask and set */ | 561 | /* mask and set */ |
@@ -693,12 +621,13 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc) | |||
693 | /* initialize power control delay registers */ | 621 | /* initialize power control delay registers */ |
694 | void ai_clkctl_init(struct si_pub *sih) | 622 | void ai_clkctl_init(struct si_pub *sih) |
695 | { | 623 | { |
624 | struct si_info *sii = container_of(sih, struct si_info, pub); | ||
696 | struct bcma_device *cc; | 625 | struct bcma_device *cc; |
697 | 626 | ||
698 | if (!(ai_get_cccaps(sih) & CC_CAP_PWR_CTL)) | 627 | if (!(ai_get_cccaps(sih) & CC_CAP_PWR_CTL)) |
699 | return; | 628 | return; |
700 | 629 | ||
701 | cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); | 630 | cc = sii->icbus->drv_cc.core; |
702 | if (cc == NULL) | 631 | if (cc == NULL) |
703 | return; | 632 | return; |
704 | 633 | ||
@@ -720,7 +649,7 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) | |||
720 | uint slowminfreq; | 649 | uint slowminfreq; |
721 | u16 fpdelay; | 650 | u16 fpdelay; |
722 | 651 | ||
723 | sii = (struct si_info *)sih; | 652 | sii = container_of(sih, struct si_info, pub); |
724 | if (ai_get_cccaps(sih) & CC_CAP_PMU) { | 653 | if (ai_get_cccaps(sih) & CC_CAP_PMU) { |
725 | fpdelay = si_pmu_fast_pwrup_delay(sih); | 654 | fpdelay = si_pmu_fast_pwrup_delay(sih); |
726 | return fpdelay; | 655 | return fpdelay; |
@@ -730,7 +659,7 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) | |||
730 | return 0; | 659 | return 0; |
731 | 660 | ||
732 | fpdelay = 0; | 661 | fpdelay = 0; |
733 | cc = ai_findcore(sih, CC_CORE_ID, 0); | 662 | cc = sii->icbus->drv_cc.core; |
734 | if (cc) { | 663 | if (cc) { |
735 | slowminfreq = ai_slowclk_freq(sih, false, cc); | 664 | slowminfreq = ai_slowclk_freq(sih, false, cc); |
736 | fpdelay = (((bcma_read32(cc, CHIPCREGOFFS(pll_on_delay)) + 2) | 665 | fpdelay = (((bcma_read32(cc, CHIPCREGOFFS(pll_on_delay)) + 2) |
@@ -752,12 +681,9 @@ bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode) | |||
752 | struct si_info *sii; | 681 | struct si_info *sii; |
753 | struct bcma_device *cc; | 682 | struct bcma_device *cc; |
754 | 683 | ||
755 | sii = (struct si_info *)sih; | 684 | sii = container_of(sih, struct si_info, pub); |
756 | |||
757 | if (PCI_FORCEHT(sih)) | ||
758 | return mode == BCMA_CLKMODE_FAST; | ||
759 | 685 | ||
760 | cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); | 686 | cc = sii->icbus->drv_cc.core; |
761 | bcma_core_set_clockmode(cc, mode); | 687 | bcma_core_set_clockmode(cc, mode); |
762 | return mode == BCMA_CLKMODE_FAST; | 688 | return mode == BCMA_CLKMODE_FAST; |
763 | } | 689 | } |
@@ -765,16 +691,10 @@ bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode) | |||
765 | void ai_pci_up(struct si_pub *sih) | 691 | void ai_pci_up(struct si_pub *sih) |
766 | { | 692 | { |
767 | struct si_info *sii; | 693 | struct si_info *sii; |
768 | struct bcma_device *cc; | ||
769 | 694 | ||
770 | sii = (struct si_info *)sih; | 695 | sii = container_of(sih, struct si_info, pub); |
771 | 696 | ||
772 | if (PCI_FORCEHT(sih)) { | 697 | if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) |
773 | cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); | ||
774 | bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST); | ||
775 | } | ||
776 | |||
777 | if (PCIE(sih)) | ||
778 | bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true); | 698 | bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true); |
779 | } | 699 | } |
780 | 700 | ||
@@ -782,26 +702,20 @@ void ai_pci_up(struct si_pub *sih) | |||
782 | void ai_pci_down(struct si_pub *sih) | 702 | void ai_pci_down(struct si_pub *sih) |
783 | { | 703 | { |
784 | struct si_info *sii; | 704 | struct si_info *sii; |
785 | struct bcma_device *cc; | ||
786 | 705 | ||
787 | sii = (struct si_info *)sih; | 706 | sii = container_of(sih, struct si_info, pub); |
788 | 707 | ||
789 | /* release FORCEHT since chip is going to "down" state */ | 708 | if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) |
790 | if (PCI_FORCEHT(sih)) { | ||
791 | cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); | ||
792 | bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC); | ||
793 | } | ||
794 | |||
795 | if (PCIE(sih)) | ||
796 | bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false); | 709 | bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false); |
797 | } | 710 | } |
798 | 711 | ||
799 | /* Enable BT-COEX & Ex-PA for 4313 */ | 712 | /* Enable BT-COEX & Ex-PA for 4313 */ |
800 | void ai_epa_4313war(struct si_pub *sih) | 713 | void ai_epa_4313war(struct si_pub *sih) |
801 | { | 714 | { |
715 | struct si_info *sii = container_of(sih, struct si_info, pub); | ||
802 | struct bcma_device *cc; | 716 | struct bcma_device *cc; |
803 | 717 | ||
804 | cc = ai_findcore(sih, CC_CORE_ID, 0); | 718 | cc = sii->icbus->drv_cc.core; |
805 | 719 | ||
806 | /* EPA Fix */ | 720 | /* EPA Fix */ |
807 | bcma_set32(cc, CHIPCREGOFFS(gpiocontrol), GPIO_CTRL_EPA_EN_MASK); | 721 | bcma_set32(cc, CHIPCREGOFFS(gpiocontrol), GPIO_CTRL_EPA_EN_MASK); |
@@ -813,7 +727,7 @@ bool ai_deviceremoved(struct si_pub *sih) | |||
813 | u32 w; | 727 | u32 w; |
814 | struct si_info *sii; | 728 | struct si_info *sii; |
815 | 729 | ||
816 | sii = (struct si_info *)sih; | 730 | sii = container_of(sih, struct si_info, pub); |
817 | 731 | ||
818 | if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI) | 732 | if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI) |
819 | return false; | 733 | return false; |
@@ -824,15 +738,3 @@ bool ai_deviceremoved(struct si_pub *sih) | |||
824 | 738 | ||
825 | return false; | 739 | return false; |
826 | } | 740 | } |
827 | |||
828 | uint ai_get_buscoretype(struct si_pub *sih) | ||
829 | { | ||
830 | struct si_info *sii = (struct si_info *)sih; | ||
831 | return sii->buscore->id.id; | ||
832 | } | ||
833 | |||
834 | uint ai_get_buscorerev(struct si_pub *sih) | ||
835 | { | ||
836 | struct si_info *sii = (struct si_info *)sih; | ||
837 | return sii->buscore->id.rev; | ||
838 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index d6fa9829af9a..89562c1fbf49 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h | |||
@@ -88,16 +88,6 @@ | |||
88 | #define CLKD_OTP 0x000f0000 | 88 | #define CLKD_OTP 0x000f0000 |
89 | #define CLKD_OTP_SHIFT 16 | 89 | #define CLKD_OTP_SHIFT 16 |
90 | 90 | ||
91 | /* Package IDs */ | ||
92 | #define BCM4717_PKG_ID 9 /* 4717 package id */ | ||
93 | #define BCM4718_PKG_ID 10 /* 4718 package id */ | ||
94 | #define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ | ||
95 | |||
96 | /* these are router chips */ | ||
97 | #define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ | ||
98 | #define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ | ||
99 | #define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ | ||
100 | |||
101 | /* dynamic clock control defines */ | 91 | /* dynamic clock control defines */ |
102 | #define LPOMINFREQ 25000 /* low power oscillator min */ | 92 | #define LPOMINFREQ 25000 /* low power oscillator min */ |
103 | #define LPOMAXFREQ 43000 /* low power oscillator max */ | 93 | #define LPOMAXFREQ 43000 /* low power oscillator max */ |
@@ -168,7 +158,6 @@ struct si_info { | |||
168 | struct si_pub pub; /* back plane public state (must be first) */ | 158 | struct si_pub pub; /* back plane public state (must be first) */ |
169 | struct bcma_bus *icbus; /* handle to soc interconnect bus */ | 159 | struct bcma_bus *icbus; /* handle to soc interconnect bus */ |
170 | struct pci_dev *pcibus; /* handle to pci bus */ | 160 | struct pci_dev *pcibus; /* handle to pci bus */ |
171 | struct bcma_device *buscore; | ||
172 | 161 | ||
173 | u32 chipst; /* chip status */ | 162 | u32 chipst; /* chip status */ |
174 | }; | 163 | }; |
@@ -183,8 +172,6 @@ struct si_info { | |||
183 | 172 | ||
184 | 173 | ||
185 | /* AMBA Interconnect exported externs */ | 174 | /* AMBA Interconnect exported externs */ |
186 | extern struct bcma_device *ai_findcore(struct si_pub *sih, | ||
187 | u16 coreid, u16 coreunit); | ||
188 | extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); | 175 | extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); |
189 | 176 | ||
190 | /* === exported functions === */ | 177 | /* === exported functions === */ |
@@ -202,9 +189,6 @@ extern void ai_pci_up(struct si_pub *sih); | |||
202 | /* Enable Ex-PA for 4313 */ | 189 | /* Enable Ex-PA for 4313 */ |
203 | extern void ai_epa_4313war(struct si_pub *sih); | 190 | extern void ai_epa_4313war(struct si_pub *sih); |
204 | 191 | ||
205 | extern uint ai_get_buscoretype(struct si_pub *sih); | ||
206 | extern uint ai_get_buscorerev(struct si_pub *sih); | ||
207 | |||
208 | static inline u32 ai_get_cccaps(struct si_pub *sih) | 192 | static inline u32 ai_get_cccaps(struct si_pub *sih) |
209 | { | 193 | { |
210 | return sih->cccaps; | 194 | return sih->cccaps; |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 2d365d3486df..9a4c63f927cb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c | |||
@@ -763,20 +763,17 @@ void brcms_c_regd_init(struct brcms_c_info *wlc) | |||
763 | int band_idx, i; | 763 | int band_idx, i; |
764 | 764 | ||
765 | /* Disable any channels not supported by the phy */ | 765 | /* Disable any channels not supported by the phy */ |
766 | for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) { | 766 | for (band_idx = 0; band_idx < wlc->pub->_nbands; band_idx++) { |
767 | if (band_idx == IEEE80211_BAND_2GHZ) | 767 | band = wlc->bandstate[band_idx]; |
768 | band = wlc->bandstate[BAND_2G_INDEX]; | ||
769 | else | ||
770 | band = wlc->bandstate[BAND_5G_INDEX]; | ||
771 | |||
772 | /* skip if band not initialized */ | ||
773 | if (band->pi == NULL) | ||
774 | continue; | ||
775 | 768 | ||
776 | wlc_phy_chanspec_band_validch(band->pi, band->bandtype, | 769 | wlc_phy_chanspec_band_validch(band->pi, band->bandtype, |
777 | &sup_chan); | 770 | &sup_chan); |
778 | 771 | ||
779 | sband = wiphy->bands[band_idx]; | 772 | if (band_idx == BAND_2G_INDEX) |
773 | sband = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
774 | else | ||
775 | sband = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
776 | |||
780 | for (i = 0; i < sband->n_channels; i++) { | 777 | for (i = 0; i < sband->n_channels; i++) { |
781 | ch = &sband->channels[i]; | 778 | ch = &sband->channels[i]; |
782 | if (!isset(sup_chan.vec, ch->hw_value)) | 779 | if (!isset(sup_chan.vec, ch->hw_value)) |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 7516639412ec..5e53305bd9a9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c | |||
@@ -573,6 +573,7 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, | |||
573 | struct dma_info *di; | 573 | struct dma_info *di; |
574 | u8 rev = core->id.rev; | 574 | u8 rev = core->id.rev; |
575 | uint size; | 575 | uint size; |
576 | struct si_info *sii = container_of(sih, struct si_info, pub); | ||
576 | 577 | ||
577 | /* allocate private info structure */ | 578 | /* allocate private info structure */ |
578 | di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); | 579 | di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); |
@@ -633,16 +634,20 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, | |||
633 | */ | 634 | */ |
634 | di->ddoffsetlow = 0; | 635 | di->ddoffsetlow = 0; |
635 | di->dataoffsetlow = 0; | 636 | di->dataoffsetlow = 0; |
636 | /* add offset for pcie with DMA64 bus */ | 637 | /* for pci bus, add offset */ |
637 | di->ddoffsetlow = 0; | 638 | if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) { |
638 | di->ddoffsethigh = SI_PCIE_DMA_H32; | 639 | /* add offset for pcie with DMA64 bus */ |
640 | di->ddoffsetlow = 0; | ||
641 | di->ddoffsethigh = SI_PCIE_DMA_H32; | ||
642 | } | ||
639 | di->dataoffsetlow = di->ddoffsetlow; | 643 | di->dataoffsetlow = di->ddoffsetlow; |
640 | di->dataoffsethigh = di->ddoffsethigh; | 644 | di->dataoffsethigh = di->ddoffsethigh; |
645 | |||
641 | /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ | 646 | /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ |
642 | if ((core->id.id == SDIOD_CORE_ID) | 647 | if ((core->id.id == BCMA_CORE_SDIO_DEV) |
643 | && ((rev > 0) && (rev <= 2))) | 648 | && ((rev > 0) && (rev <= 2))) |
644 | di->addrext = false; | 649 | di->addrext = false; |
645 | else if ((core->id.id == I2S_CORE_ID) && | 650 | else if ((core->id.id == BCMA_CORE_I2S) && |
646 | ((rev == 0) || (rev == 1))) | 651 | ((rev == 0) || (rev == 1))) |
647 | di->addrext = false; | 652 | di->addrext = false; |
648 | else | 653 | else |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 2d5a40412690..2b57f57a7927 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | |||
@@ -319,8 +319,7 @@ static void brcms_ops_stop(struct ieee80211_hw *hw) | |||
319 | return; | 319 | return; |
320 | 320 | ||
321 | spin_lock_bh(&wl->lock); | 321 | spin_lock_bh(&wl->lock); |
322 | status = brcms_c_chipmatch(wl->wlc->hw->vendorid, | 322 | status = brcms_c_chipmatch(wl->wlc->hw->d11core); |
323 | wl->wlc->hw->deviceid); | ||
324 | spin_unlock_bh(&wl->lock); | 323 | spin_unlock_bh(&wl->lock); |
325 | if (!status) { | 324 | if (!status) { |
326 | wiphy_err(wl->wiphy, | 325 | wiphy_err(wl->wiphy, |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index bb00b6528d8f..cb73f2250b11 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
@@ -269,7 +269,7 @@ struct brcms_c_bit_desc { | |||
269 | */ | 269 | */ |
270 | 270 | ||
271 | /* Starting corerev for the fifo size table */ | 271 | /* Starting corerev for the fifo size table */ |
272 | #define XMTFIFOTBL_STARTREV 20 | 272 | #define XMTFIFOTBL_STARTREV 17 |
273 | 273 | ||
274 | struct d11init { | 274 | struct d11init { |
275 | __le16 addr; | 275 | __le16 addr; |
@@ -333,6 +333,12 @@ const u8 wlc_prio2prec_map[] = { | |||
333 | }; | 333 | }; |
334 | 334 | ||
335 | static const u16 xmtfifo_sz[][NFIFO] = { | 335 | static const u16 xmtfifo_sz[][NFIFO] = { |
336 | /* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */ | ||
337 | {20, 192, 192, 21, 17, 5}, | ||
338 | /* corerev 18: */ | ||
339 | {0, 0, 0, 0, 0, 0}, | ||
340 | /* corerev 19: */ | ||
341 | {0, 0, 0, 0, 0, 0}, | ||
336 | /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ | 342 | /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ |
337 | {20, 192, 192, 21, 17, 5}, | 343 | {20, 192, 192, 21, 17, 5}, |
338 | /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ | 344 | /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ |
@@ -343,6 +349,14 @@ static const u16 xmtfifo_sz[][NFIFO] = { | |||
343 | {20, 192, 192, 21, 17, 5}, | 349 | {20, 192, 192, 21, 17, 5}, |
344 | /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ | 350 | /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ |
345 | {9, 58, 22, 14, 14, 5}, | 351 | {9, 58, 22, 14, 14, 5}, |
352 | /* corerev 25: */ | ||
353 | {0, 0, 0, 0, 0, 0}, | ||
354 | /* corerev 26: */ | ||
355 | {0, 0, 0, 0, 0, 0}, | ||
356 | /* corerev 27: */ | ||
357 | {0, 0, 0, 0, 0, 0}, | ||
358 | /* corerev 28: 2304, 14848, 5632, 3584, 3584, 1280 */ | ||
359 | {9, 58, 22, 14, 14, 5}, | ||
346 | }; | 360 | }; |
347 | 361 | ||
348 | #ifdef DEBUG | 362 | #ifdef DEBUG |
@@ -1942,7 +1956,8 @@ static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) | |||
1942 | * accesses phyreg throughput mac. This can be skipped since | 1956 | * accesses phyreg throughput mac. This can be skipped since |
1943 | * only mac reg is accessed below | 1957 | * only mac reg is accessed below |
1944 | */ | 1958 | */ |
1945 | flags |= SICF_PCLKE; | 1959 | if (D11REV_GE(wlc_hw->corerev, 18)) |
1960 | flags |= SICF_PCLKE; | ||
1946 | 1961 | ||
1947 | /* | 1962 | /* |
1948 | * TODO: test suspend/resume | 1963 | * TODO: test suspend/resume |
@@ -2023,7 +2038,8 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) | |||
2023 | * phyreg throughput mac, AND phy_reset is skipped at early stage when | 2038 | * phyreg throughput mac, AND phy_reset is skipped at early stage when |
2024 | * band->pi is invalid. need to enable PHY CLK | 2039 | * band->pi is invalid. need to enable PHY CLK |
2025 | */ | 2040 | */ |
2026 | flags |= SICF_PCLKE; | 2041 | if (D11REV_GE(wlc_hw->corerev, 18)) |
2042 | flags |= SICF_PCLKE; | ||
2027 | 2043 | ||
2028 | /* | 2044 | /* |
2029 | * reset the core | 2045 | * reset the core |
@@ -2126,8 +2142,8 @@ void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) | |||
2126 | { | 2142 | { |
2127 | struct bcma_device *core = wlc_hw->d11core; | 2143 | struct bcma_device *core = wlc_hw->d11core; |
2128 | 2144 | ||
2129 | if ((ai_get_chip_id(wlc_hw->sih) == BCM43224_CHIP_ID) || | 2145 | if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43224) || |
2130 | (ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) { | 2146 | (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) { |
2131 | if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ | 2147 | if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ |
2132 | bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082); | 2148 | bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082); |
2133 | bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); | 2149 | bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); |
@@ -2791,7 +2807,7 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) | |||
2791 | tmp = 0; | 2807 | tmp = 0; |
2792 | 2808 | ||
2793 | if (on) { | 2809 | if (on) { |
2794 | if ((ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { | 2810 | if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) { |
2795 | bcma_set32(core, D11REGOFFS(clk_ctl_st), | 2811 | bcma_set32(core, D11REGOFFS(clk_ctl_st), |
2796 | CCS_ERSRC_REQ_HT | | 2812 | CCS_ERSRC_REQ_HT | |
2797 | CCS_ERSRC_REQ_D11PLL | | 2813 | CCS_ERSRC_REQ_D11PLL | |
@@ -4218,9 +4234,8 @@ static void brcms_c_radio_timer(void *arg) | |||
4218 | } | 4234 | } |
4219 | 4235 | ||
4220 | /* common low-level watchdog code */ | 4236 | /* common low-level watchdog code */ |
4221 | static void brcms_b_watchdog(void *arg) | 4237 | static void brcms_b_watchdog(struct brcms_c_info *wlc) |
4222 | { | 4238 | { |
4223 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; | ||
4224 | struct brcms_hardware *wlc_hw = wlc->hw; | 4239 | struct brcms_hardware *wlc_hw = wlc->hw; |
4225 | 4240 | ||
4226 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); | 4241 | BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); |
@@ -4241,10 +4256,8 @@ static void brcms_b_watchdog(void *arg) | |||
4241 | } | 4256 | } |
4242 | 4257 | ||
4243 | /* common watchdog code */ | 4258 | /* common watchdog code */ |
4244 | static void brcms_c_watchdog(void *arg) | 4259 | static void brcms_c_watchdog(struct brcms_c_info *wlc) |
4245 | { | 4260 | { |
4246 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; | ||
4247 | |||
4248 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); | 4261 | BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); |
4249 | 4262 | ||
4250 | if (!wlc->pub->up) | 4263 | if (!wlc->pub->up) |
@@ -4284,7 +4297,9 @@ static void brcms_c_watchdog(void *arg) | |||
4284 | 4297 | ||
4285 | static void brcms_c_watchdog_by_timer(void *arg) | 4298 | static void brcms_c_watchdog_by_timer(void *arg) |
4286 | { | 4299 | { |
4287 | brcms_c_watchdog(arg); | 4300 | struct brcms_c_info *wlc = (struct brcms_c_info *) arg; |
4301 | |||
4302 | brcms_c_watchdog(wlc); | ||
4288 | } | 4303 | } |
4289 | 4304 | ||
4290 | static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) | 4305 | static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) |
@@ -4454,11 +4469,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, | |||
4454 | } | 4469 | } |
4455 | 4470 | ||
4456 | /* verify again the device is supported */ | 4471 | /* verify again the device is supported */ |
4457 | if (core->bus->hosttype == BCMA_HOSTTYPE_PCI && | 4472 | if (!brcms_c_chipmatch(core)) { |
4458 | !brcms_c_chipmatch(pcidev->vendor, pcidev->device)) { | 4473 | wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported device\n", |
4459 | wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " | 4474 | unit); |
4460 | "vendor/device (0x%x/0x%x)\n", | ||
4461 | unit, pcidev->vendor, pcidev->device); | ||
4462 | err = 12; | 4475 | err = 12; |
4463 | goto fail; | 4476 | goto fail; |
4464 | } | 4477 | } |
@@ -4528,7 +4541,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, | |||
4528 | else | 4541 | else |
4529 | wlc_hw->_nbands = 1; | 4542 | wlc_hw->_nbands = 1; |
4530 | 4543 | ||
4531 | if ((ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) | 4544 | if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) |
4532 | wlc_hw->_nbands = 1; | 4545 | wlc_hw->_nbands = 1; |
4533 | 4546 | ||
4534 | /* BMAC_NOTE: remove init of pub values when brcms_c_attach() | 4547 | /* BMAC_NOTE: remove init of pub values when brcms_c_attach() |
@@ -4595,8 +4608,12 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, | |||
4595 | wlc_hw->machwcap_backup = wlc_hw->machwcap; | 4608 | wlc_hw->machwcap_backup = wlc_hw->machwcap; |
4596 | 4609 | ||
4597 | /* init tx fifo size */ | 4610 | /* init tx fifo size */ |
4611 | WARN_ON((wlc_hw->corerev - XMTFIFOTBL_STARTREV) < 0 || | ||
4612 | (wlc_hw->corerev - XMTFIFOTBL_STARTREV) > | ||
4613 | ARRAY_SIZE(xmtfifo_sz)); | ||
4598 | wlc_hw->xmtfifo_sz = | 4614 | wlc_hw->xmtfifo_sz = |
4599 | xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; | 4615 | xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; |
4616 | WARN_ON(!wlc_hw->xmtfifo_sz[0]); | ||
4600 | 4617 | ||
4601 | /* Get a phy for this band */ | 4618 | /* Get a phy for this band */ |
4602 | wlc_hw->band->pi = | 4619 | wlc_hw->band->pi = |
@@ -5036,7 +5053,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) | |||
5036 | wlc_hw->wlc->pub->hw_up = true; | 5053 | wlc_hw->wlc->pub->hw_up = true; |
5037 | 5054 | ||
5038 | if ((wlc_hw->boardflags & BFL_FEM) | 5055 | if ((wlc_hw->boardflags & BFL_FEM) |
5039 | && (ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { | 5056 | && (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) { |
5040 | if (! | 5057 | if (! |
5041 | (wlc_hw->boardrev >= 0x1250 | 5058 | (wlc_hw->boardrev >= 0x1250 |
5042 | && (wlc_hw->boardflags & BFL_FEM_BT))) | 5059 | && (wlc_hw->boardflags & BFL_FEM_BT))) |
@@ -5130,7 +5147,7 @@ int brcms_c_up(struct brcms_c_info *wlc) | |||
5130 | } | 5147 | } |
5131 | 5148 | ||
5132 | if ((wlc->pub->boardflags & BFL_FEM) | 5149 | if ((wlc->pub->boardflags & BFL_FEM) |
5133 | && (ai_get_chip_id(wlc->hw->sih) == BCM4313_CHIP_ID)) { | 5150 | && (ai_get_chip_id(wlc->hw->sih) == BCMA_CHIP_ID_BCM4313)) { |
5134 | if (wlc->pub->boardrev >= 0x1250 | 5151 | if (wlc->pub->boardrev >= 0x1250 |
5135 | && (wlc->pub->boardflags & BFL_FEM_BT)) | 5152 | && (wlc->pub->boardflags & BFL_FEM_BT)) |
5136 | brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, | 5153 | brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, |
@@ -5767,8 +5784,12 @@ void brcms_c_print_txstatus(struct tx_status *txs) | |||
5767 | (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); | 5784 | (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); |
5768 | } | 5785 | } |
5769 | 5786 | ||
5770 | bool brcms_c_chipmatch(u16 vendor, u16 device) | 5787 | static bool brcms_c_chipmatch_pci(struct bcma_device *core) |
5771 | { | 5788 | { |
5789 | struct pci_dev *pcidev = core->bus->host_pci; | ||
5790 | u16 vendor = pcidev->vendor; | ||
5791 | u16 device = pcidev->device; | ||
5792 | |||
5772 | if (vendor != PCI_VENDOR_ID_BROADCOM) { | 5793 | if (vendor != PCI_VENDOR_ID_BROADCOM) { |
5773 | pr_err("unknown vendor id %04x\n", vendor); | 5794 | pr_err("unknown vendor id %04x\n", vendor); |
5774 | return false; | 5795 | return false; |
@@ -5787,6 +5808,30 @@ bool brcms_c_chipmatch(u16 vendor, u16 device) | |||
5787 | return false; | 5808 | return false; |
5788 | } | 5809 | } |
5789 | 5810 | ||
5811 | static bool brcms_c_chipmatch_soc(struct bcma_device *core) | ||
5812 | { | ||
5813 | struct bcma_chipinfo *chipinfo = &core->bus->chipinfo; | ||
5814 | |||
5815 | if (chipinfo->id == BCMA_CHIP_ID_BCM4716) | ||
5816 | return true; | ||
5817 | |||
5818 | pr_err("unknown chip id %04x\n", chipinfo->id); | ||
5819 | return false; | ||
5820 | } | ||
5821 | |||
5822 | bool brcms_c_chipmatch(struct bcma_device *core) | ||
5823 | { | ||
5824 | switch (core->bus->hosttype) { | ||
5825 | case BCMA_HOSTTYPE_PCI: | ||
5826 | return brcms_c_chipmatch_pci(core); | ||
5827 | case BCMA_HOSTTYPE_SOC: | ||
5828 | return brcms_c_chipmatch_soc(core); | ||
5829 | default: | ||
5830 | pr_err("unknown host type: %i\n", core->bus->hosttype); | ||
5831 | return false; | ||
5832 | } | ||
5833 | } | ||
5834 | |||
5790 | #if defined(DEBUG) | 5835 | #if defined(DEBUG) |
5791 | void brcms_c_print_txdesc(struct d11txh *txh) | 5836 | void brcms_c_print_txdesc(struct d11txh *txh) |
5792 | { | 5837 | { |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 264f8c4c703d..91937c5025ce 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c | |||
@@ -198,6 +198,8 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr) | |||
198 | 198 | ||
199 | void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) | 199 | void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) |
200 | { | 200 | { |
201 | struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); | ||
202 | |||
201 | if ((D11REV_GE(pi->sh->corerev, 24)) || | 203 | if ((D11REV_GE(pi->sh->corerev, 24)) || |
202 | (D11REV_IS(pi->sh->corerev, 22) | 204 | (D11REV_IS(pi->sh->corerev, 22) |
203 | && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { | 205 | && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { |
@@ -209,7 +211,8 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) | |||
209 | bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val); | 211 | bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val); |
210 | } | 212 | } |
211 | 213 | ||
212 | if (++pi->phy_wreg >= pi->phy_wreg_limit) { | 214 | if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) && |
215 | (++pi->phy_wreg >= pi->phy_wreg_limit)) { | ||
213 | (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); | 216 | (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); |
214 | pi->phy_wreg = 0; | 217 | pi->phy_wreg = 0; |
215 | } | 218 | } |
@@ -292,10 +295,13 @@ void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) | |||
292 | bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); | 295 | bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); |
293 | bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val); | 296 | bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val); |
294 | if (addr == 0x72) | 297 | if (addr == 0x72) |
295 | (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); | 298 | (void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata)); |
296 | #else | 299 | #else |
300 | struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); | ||
301 | |||
297 | bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16)); | 302 | bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16)); |
298 | if (++pi->phy_wreg >= pi->phy_wreg_limit) { | 303 | if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) && |
304 | (++pi->phy_wreg >= pi->phy_wreg_limit)) { | ||
299 | pi->phy_wreg = 0; | 305 | pi->phy_wreg = 0; |
300 | (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); | 306 | (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); |
301 | } | 307 | } |
@@ -837,7 +843,7 @@ wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, | |||
837 | pi->tbl_data_hi = tblDataHi; | 843 | pi->tbl_data_hi = tblDataHi; |
838 | pi->tbl_data_lo = tblDataLo; | 844 | pi->tbl_data_lo = tblDataLo; |
839 | 845 | ||
840 | if (pi->sh->chip == BCM43224_CHIP_ID && | 846 | if (pi->sh->chip == BCMA_CHIP_ID_BCM43224 && |
841 | pi->sh->chiprev == 1) { | 847 | pi->sh->chiprev == 1) { |
842 | pi->tbl_addr = tblAddr; | 848 | pi->tbl_addr = tblAddr; |
843 | pi->tbl_save_id = tbl_id; | 849 | pi->tbl_save_id = tbl_id; |
@@ -847,7 +853,7 @@ wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, | |||
847 | 853 | ||
848 | void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) | 854 | void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) |
849 | { | 855 | { |
850 | if ((pi->sh->chip == BCM43224_CHIP_ID) && | 856 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && |
851 | (pi->sh->chiprev == 1) && | 857 | (pi->sh->chiprev == 1) && |
852 | (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { | 858 | (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { |
853 | read_phy_reg(pi, pi->tbl_data_lo); | 859 | read_phy_reg(pi, pi->tbl_data_lo); |
@@ -881,7 +887,7 @@ wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, | |||
881 | 887 | ||
882 | for (idx = 0; idx < ptbl_info->tbl_len; idx++) { | 888 | for (idx = 0; idx < ptbl_info->tbl_len; idx++) { |
883 | 889 | ||
884 | if ((pi->sh->chip == BCM43224_CHIP_ID) && | 890 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && |
885 | (pi->sh->chiprev == 1) && | 891 | (pi->sh->chiprev == 1) && |
886 | (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { | 892 | (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { |
887 | read_phy_reg(pi, tblDataLo); | 893 | read_phy_reg(pi, tblDataLo); |
@@ -918,7 +924,7 @@ wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, | |||
918 | 924 | ||
919 | for (idx = 0; idx < ptbl_info->tbl_len; idx++) { | 925 | for (idx = 0; idx < ptbl_info->tbl_len; idx++) { |
920 | 926 | ||
921 | if ((pi->sh->chip == BCM43224_CHIP_ID) && | 927 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && |
922 | (pi->sh->chiprev == 1)) { | 928 | (pi->sh->chiprev == 1)) { |
923 | (void)read_phy_reg(pi, tblDataLo); | 929 | (void)read_phy_reg(pi, tblDataLo); |
924 | 930 | ||
@@ -2894,7 +2900,7 @@ const u8 *wlc_phy_get_ofdm_rate_lookup(void) | |||
2894 | 2900 | ||
2895 | void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) | 2901 | void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) |
2896 | { | 2902 | { |
2897 | if ((pi->sh->chip == BCM4313_CHIP_ID) && | 2903 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) && |
2898 | (pi->sh->boardflags & BFL_FEM)) { | 2904 | (pi->sh->boardflags & BFL_FEM)) { |
2899 | if (mode) { | 2905 | if (mode) { |
2900 | u16 txant = 0; | 2906 | u16 txant = 0; |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 366718146418..65db9b7458dc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c | |||
@@ -17893,6 +17893,8 @@ static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi) | |||
17893 | nphy_tpc_txgain_ipa_2g_2057rev7; | 17893 | nphy_tpc_txgain_ipa_2g_2057rev7; |
17894 | } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { | 17894 | } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { |
17895 | tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; | 17895 | tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; |
17896 | if (pi->sh->chip == BCMA_CHIP_ID_BCM47162) | ||
17897 | tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; | ||
17896 | } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { | 17898 | } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { |
17897 | tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; | 17899 | tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; |
17898 | } else { | 17900 | } else { |
@@ -19254,8 +19256,14 @@ static void wlc_phy_spurwar_nphy(struct brcms_phy *pi) | |||
19254 | case 38: | 19256 | case 38: |
19255 | case 102: | 19257 | case 102: |
19256 | case 118: | 19258 | case 118: |
19257 | nphy_adj_tone_id_buf[0] = 0; | 19259 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) && |
19258 | nphy_adj_noise_var_buf[0] = 0x0; | 19260 | (pi->sh->chippkg == BCMA_PKG_ID_BCM4717)) { |
19261 | nphy_adj_tone_id_buf[0] = 32; | ||
19262 | nphy_adj_noise_var_buf[0] = 0x21f; | ||
19263 | } else { | ||
19264 | nphy_adj_tone_id_buf[0] = 0; | ||
19265 | nphy_adj_noise_var_buf[0] = 0x0; | ||
19266 | } | ||
19259 | break; | 19267 | break; |
19260 | case 134: | 19268 | case 134: |
19261 | nphy_adj_tone_id_buf[0] = 32; | 19269 | nphy_adj_tone_id_buf[0] = 32; |
@@ -19309,8 +19317,8 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) | |||
19309 | pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; | 19317 | pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; |
19310 | 19318 | ||
19311 | if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) && | 19319 | if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) && |
19312 | ((pi->sh->chippkg == BCM4717_PKG_ID) || | 19320 | ((pi->sh->chippkg == BCMA_PKG_ID_BCM4717) || |
19313 | (pi->sh->chippkg == BCM4718_PKG_ID))) { | 19321 | (pi->sh->chippkg == BCMA_PKG_ID_BCM4718))) { |
19314 | if ((pi->sh->boardflags & BFL_EXTLNA) && | 19322 | if ((pi->sh->boardflags & BFL_EXTLNA) && |
19315 | (CHSPEC_IS2G(pi->radio_chanspec))) | 19323 | (CHSPEC_IS2G(pi->radio_chanspec))) |
19316 | ai_cc_reg(pi->sh->sih, | 19324 | ai_cc_reg(pi->sh->sih, |
@@ -19318,6 +19326,10 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) | |||
19318 | 0x40, 0x40); | 19326 | 0x40, 0x40); |
19319 | } | 19327 | } |
19320 | 19328 | ||
19329 | if ((!PHY_IPA(pi)) && (pi->sh->chip == BCMA_CHIP_ID_BCM5357)) | ||
19330 | si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA, | ||
19331 | CCTRL5357_EXTPA); | ||
19332 | |||
19321 | if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && | 19333 | if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && |
19322 | CHSPEC_IS40(pi->radio_chanspec)) { | 19334 | CHSPEC_IS40(pi->radio_chanspec)) { |
19323 | 19335 | ||
@@ -20695,12 +20707,22 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, | |||
20695 | write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | | 20707 | write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | |
20696 | RADIO_2056_SYN, 0x1f); | 20708 | RADIO_2056_SYN, 0x1f); |
20697 | 20709 | ||
20698 | write_radio_reg(pi, | 20710 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || |
20699 | RADIO_2056_SYN_PLL_LOOPFILTER4 | | 20711 | (pi->sh->chip == BCMA_CHIP_ID_BCM47162)) { |
20700 | RADIO_2056_SYN, 0xb); | 20712 | write_radio_reg(pi, |
20701 | write_radio_reg(pi, | 20713 | RADIO_2056_SYN_PLL_LOOPFILTER4 | |
20702 | RADIO_2056_SYN_PLL_CP2 | | 20714 | RADIO_2056_SYN, 0x14); |
20703 | RADIO_2056_SYN, 0x14); | 20715 | write_radio_reg(pi, |
20716 | RADIO_2056_SYN_PLL_CP2 | | ||
20717 | RADIO_2056_SYN, 0x00); | ||
20718 | } else { | ||
20719 | write_radio_reg(pi, | ||
20720 | RADIO_2056_SYN_PLL_LOOPFILTER4 | | ||
20721 | RADIO_2056_SYN, 0xb); | ||
20722 | write_radio_reg(pi, | ||
20723 | RADIO_2056_SYN_PLL_CP2 | | ||
20724 | RADIO_2056_SYN, 0x14); | ||
20725 | } | ||
20704 | } | 20726 | } |
20705 | } | 20727 | } |
20706 | 20728 | ||
@@ -20747,24 +20769,30 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, | |||
20747 | WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, | 20769 | WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, |
20748 | PADG_IDAC, 0xcc); | 20770 | PADG_IDAC, 0xcc); |
20749 | 20771 | ||
20750 | bias = 0x25; | 20772 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || |
20751 | cascbias = 0x20; | 20773 | (pi->sh->chip == BCMA_CHIP_ID_BCM47162)) { |
20774 | bias = 0x40; | ||
20775 | cascbias = 0x45; | ||
20776 | pag_boost_tune = 0x5; | ||
20777 | pgag_boost_tune = 0x33; | ||
20778 | padg_boost_tune = 0x77; | ||
20779 | mixg_boost_tune = 0x55; | ||
20780 | } else { | ||
20781 | bias = 0x25; | ||
20782 | cascbias = 0x20; | ||
20752 | 20783 | ||
20753 | if ((pi->sh->chip == | 20784 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224 || |
20754 | BCM43224_CHIP_ID) | 20785 | pi->sh->chip == BCMA_CHIP_ID_BCM43225) && |
20755 | || (pi->sh->chip == | 20786 | pi->sh->chippkg == BCMA_PKG_ID_BCM43224_FAB_SMIC) { |
20756 | BCM43225_CHIP_ID)) { | ||
20757 | if (pi->sh->chippkg == | ||
20758 | BCM43224_FAB_SMIC) { | ||
20759 | bias = 0x2a; | 20787 | bias = 0x2a; |
20760 | cascbias = 0x38; | 20788 | cascbias = 0x38; |
20761 | } | 20789 | } |
20762 | } | ||
20763 | 20790 | ||
20764 | pag_boost_tune = 0x4; | 20791 | pag_boost_tune = 0x4; |
20765 | pgag_boost_tune = 0x03; | 20792 | pgag_boost_tune = 0x03; |
20766 | padg_boost_tune = 0x77; | 20793 | padg_boost_tune = 0x77; |
20767 | mixg_boost_tune = 0x65; | 20794 | mixg_boost_tune = 0x65; |
20795 | } | ||
20768 | 20796 | ||
20769 | WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, | 20797 | WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, |
20770 | INTPAG_IMAIN_STAT, bias); | 20798 | INTPAG_IMAIN_STAT, bias); |
@@ -20863,11 +20891,10 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, | |||
20863 | 20891 | ||
20864 | cascbias = 0x30; | 20892 | cascbias = 0x30; |
20865 | 20893 | ||
20866 | if ((pi->sh->chip == BCM43224_CHIP_ID) || | 20894 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224 || |
20867 | (pi->sh->chip == BCM43225_CHIP_ID)) { | 20895 | pi->sh->chip == BCMA_CHIP_ID_BCM43225) && |
20868 | if (pi->sh->chippkg == BCM43224_FAB_SMIC) | 20896 | pi->sh->chippkg == BCMA_PKG_ID_BCM43224_FAB_SMIC) |
20869 | cascbias = 0x35; | 20897 | cascbias = 0x35; |
20870 | } | ||
20871 | 20898 | ||
20872 | pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias; | 20899 | pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias; |
20873 | 20900 | ||
@@ -21106,6 +21133,7 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, | |||
21106 | const struct nphy_sfo_cfg *ci) | 21133 | const struct nphy_sfo_cfg *ci) |
21107 | { | 21134 | { |
21108 | u16 val; | 21135 | u16 val; |
21136 | struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); | ||
21109 | 21137 | ||
21110 | val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; | 21138 | val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; |
21111 | if (CHSPEC_IS5G(chanspec) && !val) { | 21139 | if (CHSPEC_IS5G(chanspec) && !val) { |
@@ -21178,22 +21206,32 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, | |||
21178 | } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { | 21206 | } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { |
21179 | if (val == 54) | 21207 | if (val == 54) |
21180 | spuravoid = 1; | 21208 | spuravoid = 1; |
21181 | } else { | 21209 | } else if (pi->nphy_aband_spurwar_en && |
21182 | if (pi->nphy_aband_spurwar_en && | 21210 | ((val == 38) || (val == 102) || (val == 118))) { |
21183 | ((val == 38) || (val == 102) | 21211 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) |
21184 | || (val == 118))) | 21212 | && (pi->sh->chippkg == BCMA_PKG_ID_BCM4717)) { |
21213 | spuravoid = 0; | ||
21214 | } else { | ||
21185 | spuravoid = 1; | 21215 | spuravoid = 1; |
21216 | } | ||
21186 | } | 21217 | } |
21187 | 21218 | ||
21188 | if (pi->phy_spuravoid == SPURAVOID_FORCEON) | 21219 | if (pi->phy_spuravoid == SPURAVOID_FORCEON) |
21189 | spuravoid = 1; | 21220 | spuravoid = 1; |
21190 | 21221 | ||
21191 | wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); | 21222 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || |
21192 | si_pmu_spuravoid_pllupdate(pi->sh->sih, spuravoid); | 21223 | (pi->sh->chip == BCMA_CHIP_ID_BCM43225)) { |
21193 | wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); | 21224 | bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc, |
21225 | spuravoid); | ||
21226 | } else { | ||
21227 | wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); | ||
21228 | bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc, | ||
21229 | spuravoid); | ||
21230 | wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); | ||
21231 | } | ||
21194 | 21232 | ||
21195 | if ((pi->sh->chip == BCM43224_CHIP_ID) || | 21233 | if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) || |
21196 | (pi->sh->chip == BCM43225_CHIP_ID)) { | 21234 | (pi->sh->chip == BCMA_CHIP_ID_BCM43225)) { |
21197 | if (spuravoid == 1) { | 21235 | if (spuravoid == 1) { |
21198 | bcma_write16(pi->d11core, | 21236 | bcma_write16(pi->d11core, |
21199 | D11REGOFFS(tsf_clk_frac_l), | 21237 | D11REGOFFS(tsf_clk_frac_l), |
@@ -21209,7 +21247,9 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, | |||
21209 | } | 21247 | } |
21210 | } | 21248 | } |
21211 | 21249 | ||
21212 | wlapi_bmac_core_phypll_reset(pi->sh->physhim); | 21250 | if (!((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || |
21251 | (pi->sh->chip == BCMA_CHIP_ID_BCM47162))) | ||
21252 | wlapi_bmac_core_phypll_reset(pi->sh->physhim); | ||
21213 | 21253 | ||
21214 | mod_phy_reg(pi, 0x01, (0x1 << 15), | 21254 | mod_phy_reg(pi, 0x01, (0x1 << 15), |
21215 | ((spuravoid > 0) ? (0x1 << 15) : 0)); | 21255 | ((spuravoid > 0) ? (0x1 << 15) : 0)); |
@@ -22171,9 +22211,15 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi) | |||
22171 | wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, | 22211 | wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, |
22172 | &auxADC_rssi_ctrlH_save); | 22212 | &auxADC_rssi_ctrlH_save); |
22173 | 22213 | ||
22174 | radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) | 22214 | if (pi->sh->chip == BCMA_CHIP_ID_BCM5357) { |
22175 | + 82 * (auxADC_Vl) - 28861 + | 22215 | radio_temp[0] = (193 * (radio_temp[1] + radio_temp2[1]) |
22176 | 128) / 256; | 22216 | + 88 * (auxADC_Vl) - 27111 + |
22217 | 128) / 256; | ||
22218 | } else { | ||
22219 | radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) | ||
22220 | + 82 * (auxADC_Vl) - 28861 + | ||
22221 | 128) / 256; | ||
22222 | } | ||
22177 | 22223 | ||
22178 | offset = (s16) pi->phy_tempsense_offset; | 22224 | offset = (s16) pi->phy_tempsense_offset; |
22179 | 22225 | ||
@@ -24923,14 +24969,16 @@ wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains, | |||
24923 | if (txgains->useindex) { | 24969 | if (txgains->useindex) { |
24924 | phy_a4 = 15 - ((txgains->index) >> 3); | 24970 | phy_a4 = 15 - ((txgains->index) >> 3); |
24925 | if (CHSPEC_IS2G(pi->radio_chanspec)) { | 24971 | if (CHSPEC_IS2G(pi->radio_chanspec)) { |
24926 | if (NREV_GE(pi->pubpi.phy_rev, 6)) | 24972 | if (NREV_GE(pi->pubpi.phy_rev, 6) && |
24973 | pi->sh->chip == BCMA_CHIP_ID_BCM47162) { | ||
24974 | phy_a5 = 0x10f7 | (phy_a4 << 8); | ||
24975 | } else if (NREV_GE(pi->pubpi.phy_rev, 6)) { | ||
24927 | phy_a5 = 0x00f7 | (phy_a4 << 8); | 24976 | phy_a5 = 0x00f7 | (phy_a4 << 8); |
24928 | 24977 | } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { | |
24929 | else | ||
24930 | if (NREV_IS(pi->pubpi.phy_rev, 5)) | ||
24931 | phy_a5 = 0x10f7 | (phy_a4 << 8); | 24978 | phy_a5 = 0x10f7 | (phy_a4 << 8); |
24932 | else | 24979 | } else { |
24933 | phy_a5 = 0x50f7 | (phy_a4 << 8); | 24980 | phy_a5 = 0x50f7 | (phy_a4 << 8); |
24981 | } | ||
24934 | } else { | 24982 | } else { |
24935 | phy_a5 = 0x70f7 | (phy_a4 << 8); | 24983 | phy_a5 = 0x70f7 | (phy_a4 << 8); |
24936 | } | 24984 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c index 4931d29d077b..7e9df566c733 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c | |||
@@ -74,16 +74,6 @@ | |||
74 | * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary | 74 | * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary |
75 | * number to differentiate different PLLs controlled by the same PMU rev. | 75 | * number to differentiate different PLLs controlled by the same PMU rev. |
76 | */ | 76 | */ |
77 | /* pllcontrol registers: | ||
78 | * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, | ||
79 | * p1div, p2div, _bypass_sdmod | ||
80 | */ | ||
81 | #define PMU1_PLL0_PLLCTL0 0 | ||
82 | #define PMU1_PLL0_PLLCTL1 1 | ||
83 | #define PMU1_PLL0_PLLCTL2 2 | ||
84 | #define PMU1_PLL0_PLLCTL3 3 | ||
85 | #define PMU1_PLL0_PLLCTL4 4 | ||
86 | #define PMU1_PLL0_PLLCTL5 5 | ||
87 | 77 | ||
88 | /* pmu XtalFreqRatio */ | 78 | /* pmu XtalFreqRatio */ |
89 | #define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF | 79 | #define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF |
@@ -108,118 +98,14 @@ | |||
108 | #define RES4313_HT_AVAIL_RSRC 14 | 98 | #define RES4313_HT_AVAIL_RSRC 14 |
109 | #define RES4313_MACPHY_CLK_AVAIL_RSRC 15 | 99 | #define RES4313_MACPHY_CLK_AVAIL_RSRC 15 |
110 | 100 | ||
111 | /* Determine min/max rsrc masks. Value 0 leaves hardware at default. */ | ||
112 | static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) | ||
113 | { | ||
114 | u32 min_mask = 0, max_mask = 0; | ||
115 | uint rsrcs; | ||
116 | |||
117 | /* # resources */ | ||
118 | rsrcs = (ai_get_pmucaps(sih) & PCAP_RC_MASK) >> PCAP_RC_SHIFT; | ||
119 | |||
120 | /* determine min/max rsrc masks */ | ||
121 | switch (ai_get_chip_id(sih)) { | ||
122 | case BCM43224_CHIP_ID: | ||
123 | case BCM43225_CHIP_ID: | ||
124 | /* ??? */ | ||
125 | break; | ||
126 | |||
127 | case BCM4313_CHIP_ID: | ||
128 | min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) | | ||
129 | PMURES_BIT(RES4313_XTAL_PU_RSRC) | | ||
130 | PMURES_BIT(RES4313_ALP_AVAIL_RSRC) | | ||
131 | PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC); | ||
132 | max_mask = 0xffff; | ||
133 | break; | ||
134 | default: | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | *pmin = min_mask; | ||
139 | *pmax = max_mask; | ||
140 | } | ||
141 | |||
142 | void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid) | ||
143 | { | ||
144 | u32 tmp = 0; | ||
145 | struct bcma_device *core; | ||
146 | |||
147 | /* switch to chipc */ | ||
148 | core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); | ||
149 | |||
150 | switch (ai_get_chip_id(sih)) { | ||
151 | case BCM43224_CHIP_ID: | ||
152 | case BCM43225_CHIP_ID: | ||
153 | if (spuravoid == 1) { | ||
154 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
155 | PMU1_PLL0_PLLCTL0); | ||
156 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
157 | 0x11500010); | ||
158 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
159 | PMU1_PLL0_PLLCTL1); | ||
160 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
161 | 0x000C0C06); | ||
162 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
163 | PMU1_PLL0_PLLCTL2); | ||
164 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
165 | 0x0F600a08); | ||
166 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
167 | PMU1_PLL0_PLLCTL3); | ||
168 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
169 | 0x00000000); | ||
170 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
171 | PMU1_PLL0_PLLCTL4); | ||
172 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
173 | 0x2001E920); | ||
174 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
175 | PMU1_PLL0_PLLCTL5); | ||
176 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
177 | 0x88888815); | ||
178 | } else { | ||
179 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
180 | PMU1_PLL0_PLLCTL0); | ||
181 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
182 | 0x11100010); | ||
183 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
184 | PMU1_PLL0_PLLCTL1); | ||
185 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
186 | 0x000c0c06); | ||
187 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
188 | PMU1_PLL0_PLLCTL2); | ||
189 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
190 | 0x03000a08); | ||
191 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
192 | PMU1_PLL0_PLLCTL3); | ||
193 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
194 | 0x00000000); | ||
195 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
196 | PMU1_PLL0_PLLCTL4); | ||
197 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
198 | 0x200005c0); | ||
199 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), | ||
200 | PMU1_PLL0_PLLCTL5); | ||
201 | bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), | ||
202 | 0x88888815); | ||
203 | } | ||
204 | tmp = 1 << 10; | ||
205 | break; | ||
206 | |||
207 | default: | ||
208 | /* bail out */ | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | bcma_set32(core, CHIPCREGOFFS(pmucontrol), tmp); | ||
213 | } | ||
214 | |||
215 | u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) | 101 | u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) |
216 | { | 102 | { |
217 | uint delay = PMU_MAX_TRANSITION_DLY; | 103 | uint delay = PMU_MAX_TRANSITION_DLY; |
218 | 104 | ||
219 | switch (ai_get_chip_id(sih)) { | 105 | switch (ai_get_chip_id(sih)) { |
220 | case BCM43224_CHIP_ID: | 106 | case BCMA_CHIP_ID_BCM43224: |
221 | case BCM43225_CHIP_ID: | 107 | case BCMA_CHIP_ID_BCM43225: |
222 | case BCM4313_CHIP_ID: | 108 | case BCMA_CHIP_ID_BCM4313: |
223 | delay = 3700; | 109 | delay = 3700; |
224 | break; | 110 | break; |
225 | default: | 111 | default: |
@@ -270,9 +156,9 @@ u32 si_pmu_alp_clock(struct si_pub *sih) | |||
270 | return clock; | 156 | return clock; |
271 | 157 | ||
272 | switch (ai_get_chip_id(sih)) { | 158 | switch (ai_get_chip_id(sih)) { |
273 | case BCM43224_CHIP_ID: | 159 | case BCMA_CHIP_ID_BCM43224: |
274 | case BCM43225_CHIP_ID: | 160 | case BCMA_CHIP_ID_BCM43225: |
275 | case BCM4313_CHIP_ID: | 161 | case BCMA_CHIP_ID_BCM4313: |
276 | /* always 20Mhz */ | 162 | /* always 20Mhz */ |
277 | clock = 20000 * 1000; | 163 | clock = 20000 * 1000; |
278 | break; | 164 | break; |
@@ -283,51 +169,9 @@ u32 si_pmu_alp_clock(struct si_pub *sih) | |||
283 | return clock; | 169 | return clock; |
284 | } | 170 | } |
285 | 171 | ||
286 | /* initialize PMU */ | ||
287 | void si_pmu_init(struct si_pub *sih) | ||
288 | { | ||
289 | struct bcma_device *core; | ||
290 | |||
291 | /* select chipc */ | ||
292 | core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); | ||
293 | |||
294 | if (ai_get_pmurev(sih) == 1) | ||
295 | bcma_mask32(core, CHIPCREGOFFS(pmucontrol), | ||
296 | ~PCTL_NOILP_ON_WAIT); | ||
297 | else if (ai_get_pmurev(sih) >= 2) | ||
298 | bcma_set32(core, CHIPCREGOFFS(pmucontrol), PCTL_NOILP_ON_WAIT); | ||
299 | } | ||
300 | |||
301 | /* initialize PMU resources */ | ||
302 | void si_pmu_res_init(struct si_pub *sih) | ||
303 | { | ||
304 | struct bcma_device *core; | ||
305 | u32 min_mask = 0, max_mask = 0; | ||
306 | |||
307 | /* select to chipc */ | ||
308 | core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); | ||
309 | |||
310 | /* Determine min/max rsrc masks */ | ||
311 | si_pmu_res_masks(sih, &min_mask, &max_mask); | ||
312 | |||
313 | /* It is required to program max_mask first and then min_mask */ | ||
314 | |||
315 | /* Program max resource mask */ | ||
316 | |||
317 | if (max_mask) | ||
318 | bcma_write32(core, CHIPCREGOFFS(max_res_mask), max_mask); | ||
319 | |||
320 | /* Program min resource mask */ | ||
321 | |||
322 | if (min_mask) | ||
323 | bcma_write32(core, CHIPCREGOFFS(min_res_mask), min_mask); | ||
324 | |||
325 | /* Add some delay; allow resources to come up and settle. */ | ||
326 | mdelay(2); | ||
327 | } | ||
328 | |||
329 | u32 si_pmu_measure_alpclk(struct si_pub *sih) | 172 | u32 si_pmu_measure_alpclk(struct si_pub *sih) |
330 | { | 173 | { |
174 | struct si_info *sii = container_of(sih, struct si_info, pub); | ||
331 | struct bcma_device *core; | 175 | struct bcma_device *core; |
332 | u32 alp_khz; | 176 | u32 alp_khz; |
333 | 177 | ||
@@ -335,7 +179,7 @@ u32 si_pmu_measure_alpclk(struct si_pub *sih) | |||
335 | return 0; | 179 | return 0; |
336 | 180 | ||
337 | /* Remember original core before switch to chipc */ | 181 | /* Remember original core before switch to chipc */ |
338 | core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); | 182 | core = sii->icbus->drv_cc.core; |
339 | 183 | ||
340 | if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { | 184 | if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { |
341 | u32 ilp_ctr, alp_hz; | 185 | u32 ilp_ctr, alp_hz; |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h index 3e39c5e0f9ff..f7cff873578b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h | |||
@@ -26,10 +26,7 @@ extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); | |||
26 | extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); | 26 | extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); |
27 | extern u32 si_pmu_alp_clock(struct si_pub *sih); | 27 | extern u32 si_pmu_alp_clock(struct si_pub *sih); |
28 | extern void si_pmu_pllupd(struct si_pub *sih); | 28 | extern void si_pmu_pllupd(struct si_pub *sih); |
29 | extern void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid); | ||
30 | extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); | 29 | extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); |
31 | extern void si_pmu_init(struct si_pub *sih); | ||
32 | extern void si_pmu_res_init(struct si_pub *sih); | ||
33 | extern u32 si_pmu_measure_alpclk(struct si_pub *sih); | 30 | extern u32 si_pmu_measure_alpclk(struct si_pub *sih); |
34 | 31 | ||
35 | #endif /* _BRCM_PMU_H_ */ | 32 | #endif /* _BRCM_PMU_H_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index aa5d67f8d874..5855f4fd16dc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h | |||
@@ -311,7 +311,7 @@ extern uint brcms_c_detach(struct brcms_c_info *wlc); | |||
311 | extern int brcms_c_up(struct brcms_c_info *wlc); | 311 | extern int brcms_c_up(struct brcms_c_info *wlc); |
312 | extern uint brcms_c_down(struct brcms_c_info *wlc); | 312 | extern uint brcms_c_down(struct brcms_c_info *wlc); |
313 | 313 | ||
314 | extern bool brcms_c_chipmatch(u16 vendor, u16 device); | 314 | extern bool brcms_c_chipmatch(struct bcma_device *core); |
315 | extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx); | 315 | extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx); |
316 | extern void brcms_c_reset(struct brcms_c_info *wlc); | 316 | extern void brcms_c_reset(struct brcms_c_info *wlc); |
317 | 317 | ||
diff --git a/drivers/net/wireless/brcm80211/include/soc.h b/drivers/net/wireless/brcm80211/include/soc.h index 4e9b7e4827ea..123cfa854a0d 100644 --- a/drivers/net/wireless/brcm80211/include/soc.h +++ b/drivers/net/wireless/brcm80211/include/soc.h | |||
@@ -19,68 +19,6 @@ | |||
19 | 19 | ||
20 | #define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ | 20 | #define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ |
21 | 21 | ||
22 | /* core codes */ | ||
23 | #define NODEV_CORE_ID 0x700 /* Invalid coreid */ | ||
24 | #define CC_CORE_ID 0x800 /* chipcommon core */ | ||
25 | #define ILINE20_CORE_ID 0x801 /* iline20 core */ | ||
26 | #define SRAM_CORE_ID 0x802 /* sram core */ | ||
27 | #define SDRAM_CORE_ID 0x803 /* sdram core */ | ||
28 | #define PCI_CORE_ID 0x804 /* pci core */ | ||
29 | #define MIPS_CORE_ID 0x805 /* mips core */ | ||
30 | #define ENET_CORE_ID 0x806 /* enet mac core */ | ||
31 | #define CODEC_CORE_ID 0x807 /* v90 codec core */ | ||
32 | #define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ | ||
33 | #define ADSL_CORE_ID 0x809 /* ADSL core */ | ||
34 | #define ILINE100_CORE_ID 0x80a /* iline100 core */ | ||
35 | #define IPSEC_CORE_ID 0x80b /* ipsec core */ | ||
36 | #define UTOPIA_CORE_ID 0x80c /* utopia core */ | ||
37 | #define PCMCIA_CORE_ID 0x80d /* pcmcia core */ | ||
38 | #define SOCRAM_CORE_ID 0x80e /* internal memory core */ | ||
39 | #define MEMC_CORE_ID 0x80f /* memc sdram core */ | ||
40 | #define OFDM_CORE_ID 0x810 /* OFDM phy core */ | ||
41 | #define EXTIF_CORE_ID 0x811 /* external interface core */ | ||
42 | #define D11_CORE_ID 0x812 /* 802.11 MAC core */ | ||
43 | #define APHY_CORE_ID 0x813 /* 802.11a phy core */ | ||
44 | #define BPHY_CORE_ID 0x814 /* 802.11b phy core */ | ||
45 | #define GPHY_CORE_ID 0x815 /* 802.11g phy core */ | ||
46 | #define MIPS33_CORE_ID 0x816 /* mips3302 core */ | ||
47 | #define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ | ||
48 | #define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ | ||
49 | #define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ | ||
50 | #define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ | ||
51 | #define SDIOH_CORE_ID 0x81b /* sdio host core */ | ||
52 | #define ROBO_CORE_ID 0x81c /* roboswitch core */ | ||
53 | #define ATA100_CORE_ID 0x81d /* parallel ATA core */ | ||
54 | #define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ | ||
55 | #define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ | ||
56 | #define PCIE_CORE_ID 0x820 /* pci express core */ | ||
57 | #define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ | ||
58 | #define SRAMC_CORE_ID 0x822 /* SRAM controller core */ | ||
59 | #define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ | ||
60 | #define ARM11_CORE_ID 0x824 /* ARM 1176 core */ | ||
61 | #define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ | ||
62 | #define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ | ||
63 | #define PMU_CORE_ID 0x827 /* PMU core */ | ||
64 | #define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ | ||
65 | #define SDIOD_CORE_ID 0x829 /* SDIO device core */ | ||
66 | #define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ | ||
67 | #define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ | ||
68 | #define MIPS74K_CORE_ID 0x82c /* mips 74k core */ | ||
69 | #define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ | ||
70 | #define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ | ||
71 | #define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ | ||
72 | #define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ | ||
73 | #define SC_CORE_ID 0x831 /* shared common core */ | ||
74 | #define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ | ||
75 | #define SPIH_CORE_ID 0x833 /* SPI host core */ | ||
76 | #define I2S_CORE_ID 0x834 /* I2S core */ | ||
77 | #define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ | ||
78 | #define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ | ||
79 | #define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ | ||
80 | #define DEF_AI_COMP 0xfff /* Default component, in ai chips it | ||
81 | * maps all unused address ranges | ||
82 | */ | ||
83 | |||
84 | /* Common core control flags */ | 22 | /* Common core control flags */ |
85 | #define SICF_BIST_EN 0x8000 | 23 | #define SICF_BIST_EN 0x8000 |
86 | #define SICF_PME_EN 0x4000 | 24 | #define SICF_PME_EN 0x4000 |
diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index 4b10157d8686..d4fd29ad90dc 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c | |||
@@ -946,7 +946,7 @@ il3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | |||
946 | case IEEE80211_BAND_5GHZ: | 946 | case IEEE80211_BAND_5GHZ: |
947 | rs_sta->expected_tpt = il3945_expected_tpt_a; | 947 | rs_sta->expected_tpt = il3945_expected_tpt_a; |
948 | break; | 948 | break; |
949 | case IEEE80211_NUM_BANDS: | 949 | default: |
950 | BUG(); | 950 | BUG(); |
951 | break; | 951 | break; |
952 | } | 952 | } |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 64811cd91635..97bea16f3592 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -190,6 +190,44 @@ enum { | |||
190 | REPLY_MAX = 0xff | 190 | REPLY_MAX = 0xff |
191 | }; | 191 | }; |
192 | 192 | ||
193 | /* | ||
194 | * Minimum number of queues. MAX_NUM is defined in hw specific files. | ||
195 | * Set the minimum to accommodate | ||
196 | * - 4 standard TX queues | ||
197 | * - the command queue | ||
198 | * - 4 PAN TX queues | ||
199 | * - the PAN multicast queue, and | ||
200 | * - the AUX (TX during scan dwell) queue. | ||
201 | */ | ||
202 | #define IWL_MIN_NUM_QUEUES 11 | ||
203 | |||
204 | /* | ||
205 | * Command queue depends on iPAN support. | ||
206 | */ | ||
207 | #define IWL_DEFAULT_CMD_QUEUE_NUM 4 | ||
208 | #define IWL_IPAN_CMD_QUEUE_NUM 9 | ||
209 | |||
210 | #define IWL_TX_FIFO_BK 0 /* shared */ | ||
211 | #define IWL_TX_FIFO_BE 1 | ||
212 | #define IWL_TX_FIFO_VI 2 /* shared */ | ||
213 | #define IWL_TX_FIFO_VO 3 | ||
214 | #define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK | ||
215 | #define IWL_TX_FIFO_BE_IPAN 4 | ||
216 | #define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI | ||
217 | #define IWL_TX_FIFO_VO_IPAN 5 | ||
218 | /* re-uses the VO FIFO, uCode will properly flush/schedule */ | ||
219 | #define IWL_TX_FIFO_AUX 5 | ||
220 | #define IWL_TX_FIFO_UNUSED 255 | ||
221 | |||
222 | #define IWLAGN_CMD_FIFO_NUM 7 | ||
223 | |||
224 | /* | ||
225 | * This queue number is required for proper operation | ||
226 | * because the ucode will stop/start the scheduler as | ||
227 | * required. | ||
228 | */ | ||
229 | #define IWL_IPAN_MCAST_QUEUE 8 | ||
230 | |||
193 | /****************************************************************************** | 231 | /****************************************************************************** |
194 | * (0) | 232 | * (0) |
195 | * Commonly used structures and definitions: | 233 | * Commonly used structures and definitions: |
@@ -755,8 +793,6 @@ struct iwl_qosparam_cmd { | |||
755 | #define IWLAGN_BROADCAST_ID 15 | 793 | #define IWLAGN_BROADCAST_ID 15 |
756 | #define IWLAGN_STATION_COUNT 16 | 794 | #define IWLAGN_STATION_COUNT 16 |
757 | 795 | ||
758 | #define IWL_INVALID_STATION 255 | ||
759 | #define IWL_MAX_TID_COUNT 8 | ||
760 | #define IWL_TID_NON_QOS IWL_MAX_TID_COUNT | 796 | #define IWL_TID_NON_QOS IWL_MAX_TID_COUNT |
761 | 797 | ||
762 | #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) | 798 | #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index b0eff1c340c7..46782f1102ac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c | |||
@@ -83,7 +83,7 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ | |||
83 | #define DEBUGFS_READ_FILE_OPS(name) \ | 83 | #define DEBUGFS_READ_FILE_OPS(name) \ |
84 | DEBUGFS_READ_FUNC(name); \ | 84 | DEBUGFS_READ_FUNC(name); \ |
85 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 85 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
86 | .read = iwl_dbgfs_##name##_read, \ | 86 | .read = iwl_dbgfs_##name##_read, \ |
87 | .open = simple_open, \ | 87 | .open = simple_open, \ |
88 | .llseek = generic_file_llseek, \ | 88 | .llseek = generic_file_llseek, \ |
89 | }; | 89 | }; |
@@ -2255,6 +2255,10 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, | |||
2255 | char buf[8]; | 2255 | char buf[8]; |
2256 | int buf_size; | 2256 | int buf_size; |
2257 | 2257 | ||
2258 | /* check that the interface is up */ | ||
2259 | if (!iwl_is_ready(priv)) | ||
2260 | return -EAGAIN; | ||
2261 | |||
2258 | memset(buf, 0, sizeof(buf)); | 2262 | memset(buf, 0, sizeof(buf)); |
2259 | buf_size = min(count, sizeof(buf) - 1); | 2263 | buf_size = min(count, sizeof(buf) - 1); |
2260 | if (copy_from_user(buf, user_buf, buf_size)) | 2264 | if (copy_from_user(buf, user_buf, buf_size)) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 54cf085ddc89..054f728f6266 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h | |||
@@ -90,22 +90,6 @@ | |||
90 | 90 | ||
91 | #define IWL_NUM_SCAN_RATES (2) | 91 | #define IWL_NUM_SCAN_RATES (2) |
92 | 92 | ||
93 | /* | ||
94 | * Minimum number of queues. MAX_NUM is defined in hw specific files. | ||
95 | * Set the minimum to accommodate | ||
96 | * - 4 standard TX queues | ||
97 | * - the command queue | ||
98 | * - 4 PAN TX queues | ||
99 | * - the PAN multicast queue, and | ||
100 | * - the AUX (TX during scan dwell) queue. | ||
101 | */ | ||
102 | #define IWL_MIN_NUM_QUEUES 11 | ||
103 | |||
104 | /* | ||
105 | * Command queue depends on iPAN support. | ||
106 | */ | ||
107 | #define IWL_DEFAULT_CMD_QUEUE_NUM 4 | ||
108 | #define IWL_IPAN_CMD_QUEUE_NUM 9 | ||
109 | 93 | ||
110 | #define IEEE80211_DATA_LEN 2304 | 94 | #define IEEE80211_DATA_LEN 2304 |
111 | #define IEEE80211_4ADDR_LEN 30 | 95 | #define IEEE80211_4ADDR_LEN 30 |
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index abfd7916bde6..612f05d757db 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -518,49 +518,6 @@ static void iwl_bg_tx_flush(struct work_struct *work) | |||
518 | * queue/FIFO/AC mapping definitions | 518 | * queue/FIFO/AC mapping definitions |
519 | */ | 519 | */ |
520 | 520 | ||
521 | #define IWL_TX_FIFO_BK 0 /* shared */ | ||
522 | #define IWL_TX_FIFO_BE 1 | ||
523 | #define IWL_TX_FIFO_VI 2 /* shared */ | ||
524 | #define IWL_TX_FIFO_VO 3 | ||
525 | #define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK | ||
526 | #define IWL_TX_FIFO_BE_IPAN 4 | ||
527 | #define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI | ||
528 | #define IWL_TX_FIFO_VO_IPAN 5 | ||
529 | /* re-uses the VO FIFO, uCode will properly flush/schedule */ | ||
530 | #define IWL_TX_FIFO_AUX 5 | ||
531 | #define IWL_TX_FIFO_UNUSED -1 | ||
532 | |||
533 | #define IWLAGN_CMD_FIFO_NUM 7 | ||
534 | |||
535 | /* | ||
536 | * This queue number is required for proper operation | ||
537 | * because the ucode will stop/start the scheduler as | ||
538 | * required. | ||
539 | */ | ||
540 | #define IWL_IPAN_MCAST_QUEUE 8 | ||
541 | |||
542 | static const u8 iwlagn_default_queue_to_tx_fifo[] = { | ||
543 | IWL_TX_FIFO_VO, | ||
544 | IWL_TX_FIFO_VI, | ||
545 | IWL_TX_FIFO_BE, | ||
546 | IWL_TX_FIFO_BK, | ||
547 | IWLAGN_CMD_FIFO_NUM, | ||
548 | }; | ||
549 | |||
550 | static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { | ||
551 | IWL_TX_FIFO_VO, | ||
552 | IWL_TX_FIFO_VI, | ||
553 | IWL_TX_FIFO_BE, | ||
554 | IWL_TX_FIFO_BK, | ||
555 | IWL_TX_FIFO_BK_IPAN, | ||
556 | IWL_TX_FIFO_BE_IPAN, | ||
557 | IWL_TX_FIFO_VI_IPAN, | ||
558 | IWL_TX_FIFO_VO_IPAN, | ||
559 | IWL_TX_FIFO_BE_IPAN, | ||
560 | IWLAGN_CMD_FIFO_NUM, | ||
561 | IWL_TX_FIFO_AUX, | ||
562 | }; | ||
563 | |||
564 | static const u8 iwlagn_bss_ac_to_fifo[] = { | 521 | static const u8 iwlagn_bss_ac_to_fifo[] = { |
565 | IWL_TX_FIFO_VO, | 522 | IWL_TX_FIFO_VO, |
566 | IWL_TX_FIFO_VI, | 523 | IWL_TX_FIFO_VI, |
@@ -1350,6 +1307,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1350 | else | 1307 | else |
1351 | trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; | 1308 | trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; |
1352 | trans_cfg.command_names = iwl_dvm_cmd_strings; | 1309 | trans_cfg.command_names = iwl_dvm_cmd_strings; |
1310 | trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; | ||
1353 | 1311 | ||
1354 | WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < | 1312 | WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < |
1355 | priv->cfg->base_params->num_of_queues); | 1313 | priv->cfg->base_params->num_of_queues); |
@@ -1363,15 +1321,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1363 | if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { | 1321 | if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { |
1364 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; | 1322 | priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; |
1365 | trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; | 1323 | trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; |
1366 | trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; | ||
1367 | trans_cfg.n_queue_to_fifo = | ||
1368 | ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); | ||
1369 | } else { | 1324 | } else { |
1370 | priv->sta_key_max_num = STA_KEY_MAX_NUM; | 1325 | priv->sta_key_max_num = STA_KEY_MAX_NUM; |
1371 | trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; | 1326 | trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; |
1372 | trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; | ||
1373 | trans_cfg.n_queue_to_fifo = | ||
1374 | ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); | ||
1375 | } | 1327 | } |
1376 | 1328 | ||
1377 | /* Configure transport layer */ | 1329 | /* Configure transport layer */ |
@@ -1460,9 +1412,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1460 | ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; | 1412 | ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; |
1461 | priv->sta_key_max_num = STA_KEY_MAX_NUM; | 1413 | priv->sta_key_max_num = STA_KEY_MAX_NUM; |
1462 | trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; | 1414 | trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; |
1463 | trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; | ||
1464 | trans_cfg.n_queue_to_fifo = | ||
1465 | ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); | ||
1466 | 1415 | ||
1467 | /* Configure transport layer again*/ | 1416 | /* Configure transport layer again*/ |
1468 | iwl_trans_configure(priv->trans, &trans_cfg); | 1417 | iwl_trans_configure(priv->trans, &trans_cfg); |
@@ -1480,9 +1429,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1480 | atomic_set(&priv->queue_stop_count[i], 0); | 1429 | atomic_set(&priv->queue_stop_count[i], 0); |
1481 | } | 1430 | } |
1482 | 1431 | ||
1483 | WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] != | ||
1484 | IWLAGN_CMD_FIFO_NUM); | ||
1485 | |||
1486 | if (iwl_init_drv(priv)) | 1432 | if (iwl_init_drv(priv)) |
1487 | goto out_free_eeprom; | 1433 | goto out_free_eeprom; |
1488 | 1434 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 6633074258c7..e3467fa86899 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c | |||
@@ -396,15 +396,21 @@ static u16 iwl_get_active_dwell_time(struct iwl_priv *priv, | |||
396 | static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) | 396 | static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) |
397 | { | 397 | { |
398 | struct iwl_rxon_context *ctx; | 398 | struct iwl_rxon_context *ctx; |
399 | int limits[NUM_IWL_RXON_CTX] = {}; | ||
400 | int n_active = 0; | ||
401 | u16 limit; | ||
402 | |||
403 | BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); | ||
399 | 404 | ||
400 | /* | 405 | /* |
401 | * If we're associated, we clamp the dwell time 98% | 406 | * If we're associated, we clamp the dwell time 98% |
402 | * of the smallest beacon interval (minus 2 * channel | 407 | * of the beacon interval (minus 2 * channel tune time) |
403 | * tune time) | 408 | * If both contexts are active, we have to restrict to |
409 | * 1/2 of the minimum of them, because they might be in | ||
410 | * lock-step with the time inbetween only half of what | ||
411 | * time we'd have in each of them. | ||
404 | */ | 412 | */ |
405 | for_each_context(priv, ctx) { | 413 | for_each_context(priv, ctx) { |
406 | u16 value; | ||
407 | |||
408 | switch (ctx->staging.dev_type) { | 414 | switch (ctx->staging.dev_type) { |
409 | case RXON_DEV_TYPE_P2P: | 415 | case RXON_DEV_TYPE_P2P: |
410 | /* no timing constraints */ | 416 | /* no timing constraints */ |
@@ -424,14 +430,25 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) | |||
424 | break; | 430 | break; |
425 | } | 431 | } |
426 | 432 | ||
427 | value = ctx->beacon_int; | 433 | limits[n_active++] = ctx->beacon_int ?: IWL_PASSIVE_DWELL_BASE; |
428 | if (!value) | ||
429 | value = IWL_PASSIVE_DWELL_BASE; | ||
430 | value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | ||
431 | dwell_time = min(value, dwell_time); | ||
432 | } | 434 | } |
433 | 435 | ||
434 | return dwell_time; | 436 | switch (n_active) { |
437 | case 0: | ||
438 | return dwell_time; | ||
439 | case 2: | ||
440 | limit = (limits[1] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | ||
441 | limit /= 2; | ||
442 | dwell_time = min(limit, dwell_time); | ||
443 | /* fall through to limit further */ | ||
444 | case 1: | ||
445 | limit = (limits[0] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | ||
446 | limit /= n_active; | ||
447 | return min(limit, dwell_time); | ||
448 | default: | ||
449 | WARN_ON_ONCE(1); | ||
450 | return dwell_time; | ||
451 | } | ||
435 | } | 452 | } |
436 | 453 | ||
437 | static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, | 454 | static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index b3a314ba48c7..6d8d6dd7943f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c | |||
@@ -226,13 +226,50 @@ int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) | |||
226 | return ret; | 226 | return ret; |
227 | } | 227 | } |
228 | 228 | ||
229 | static const u8 iwlagn_default_queue_to_tx_fifo[] = { | ||
230 | IWL_TX_FIFO_VO, | ||
231 | IWL_TX_FIFO_VI, | ||
232 | IWL_TX_FIFO_BE, | ||
233 | IWL_TX_FIFO_BK, | ||
234 | }; | ||
235 | |||
236 | static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { | ||
237 | IWL_TX_FIFO_VO, | ||
238 | IWL_TX_FIFO_VI, | ||
239 | IWL_TX_FIFO_BE, | ||
240 | IWL_TX_FIFO_BK, | ||
241 | IWL_TX_FIFO_BK_IPAN, | ||
242 | IWL_TX_FIFO_BE_IPAN, | ||
243 | IWL_TX_FIFO_VI_IPAN, | ||
244 | IWL_TX_FIFO_VO_IPAN, | ||
245 | IWL_TX_FIFO_BE_IPAN, | ||
246 | IWL_TX_FIFO_UNUSED, | ||
247 | IWL_TX_FIFO_AUX, | ||
248 | }; | ||
229 | 249 | ||
230 | static int iwl_alive_notify(struct iwl_priv *priv) | 250 | static int iwl_alive_notify(struct iwl_priv *priv) |
231 | { | 251 | { |
252 | const u8 *queue_to_txf; | ||
253 | u8 n_queues; | ||
232 | int ret; | 254 | int ret; |
255 | int i; | ||
233 | 256 | ||
234 | iwl_trans_fw_alive(priv->trans); | 257 | iwl_trans_fw_alive(priv->trans); |
235 | 258 | ||
259 | if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN && | ||
260 | priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE) { | ||
261 | n_queues = ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); | ||
262 | queue_to_txf = iwlagn_ipan_queue_to_tx_fifo; | ||
263 | } else { | ||
264 | n_queues = ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); | ||
265 | queue_to_txf = iwlagn_default_queue_to_tx_fifo; | ||
266 | } | ||
267 | |||
268 | for (i = 0; i < n_queues; i++) | ||
269 | if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) | ||
270 | iwl_trans_ac_txq_enable(priv->trans, i, | ||
271 | queue_to_txf[i]); | ||
272 | |||
236 | priv->passive_no_rx = false; | 273 | priv->passive_no_rx = false; |
237 | priv->transport_queue_stop = 0; | 274 | priv->transport_queue_stop = 0; |
238 | 275 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c index 0f8fcd1d4fe2..87535a67de76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.c +++ b/drivers/net/wireless/iwlwifi/iwl-debug.c | |||
@@ -61,6 +61,9 @@ | |||
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | 63 | ||
64 | #define DEBUG | ||
65 | |||
66 | #include <linux/device.h> | ||
64 | #include <linux/interrupt.h> | 67 | #include <linux/interrupt.h> |
65 | #include <linux/export.h> | 68 | #include <linux/export.h> |
66 | #include "iwl-debug.h" | 69 | #include "iwl-debug.h" |
@@ -124,7 +127,7 @@ void __iwl_dbg(struct device *dev, | |||
124 | #ifdef CONFIG_IWLWIFI_DEBUG | 127 | #ifdef CONFIG_IWLWIFI_DEBUG |
125 | if (iwl_have_debug_level(level) && | 128 | if (iwl_have_debug_level(level) && |
126 | (!limit || net_ratelimit())) | 129 | (!limit || net_ratelimit())) |
127 | dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', | 130 | dev_dbg(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', |
128 | function, &vaf); | 131 | function, &vaf); |
129 | #endif | 132 | #endif |
130 | trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); | 133 | trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 65364793021f..06ca505bb2cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h | |||
@@ -176,7 +176,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, | |||
176 | #undef TRACE_SYSTEM | 176 | #undef TRACE_SYSTEM |
177 | #define TRACE_SYSTEM iwlwifi_msg | 177 | #define TRACE_SYSTEM iwlwifi_msg |
178 | 178 | ||
179 | #define MAX_MSG_LEN 100 | 179 | #define MAX_MSG_LEN 110 |
180 | 180 | ||
181 | DECLARE_EVENT_CLASS(iwlwifi_msg_event, | 181 | DECLARE_EVENT_CLASS(iwlwifi_msg_event, |
182 | TP_PROTO(struct va_format *vaf), | 182 | TP_PROTO(struct va_format *vaf), |
@@ -189,7 +189,7 @@ DECLARE_EVENT_CLASS(iwlwifi_msg_event, | |||
189 | MAX_MSG_LEN, vaf->fmt, | 189 | MAX_MSG_LEN, vaf->fmt, |
190 | *vaf->va) >= MAX_MSG_LEN); | 190 | *vaf->va) >= MAX_MSG_LEN); |
191 | ), | 191 | ), |
192 | TP_printk("%s", (char *)__get_dynamic_array(msg)) | 192 | TP_printk("%s", __get_str(msg)) |
193 | ); | 193 | ); |
194 | 194 | ||
195 | DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, | 195 | DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index a175997e7829..cc41cfaedfbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1013,6 +1013,7 @@ struct iwl_mod_params iwlwifi_mod_params = { | |||
1013 | .power_level = IWL_POWER_INDEX_1, | 1013 | .power_level = IWL_POWER_INDEX_1, |
1014 | .bt_ch_announce = true, | 1014 | .bt_ch_announce = true, |
1015 | .auto_agg = true, | 1015 | .auto_agg = true, |
1016 | .wd_disable = true, | ||
1016 | /* the rest are 0 by default */ | 1017 | /* the rest are 0 by default */ |
1017 | }; | 1018 | }; |
1018 | EXPORT_SYMBOL_GPL(iwlwifi_mod_params); | 1019 | EXPORT_SYMBOL_GPL(iwlwifi_mod_params); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 00efde8e5536..867d8e194da4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -290,16 +290,17 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | |||
290 | * currently supports | 290 | * currently supports |
291 | */ | 291 | */ |
292 | #define IWL_MAX_HW_QUEUES 32 | 292 | #define IWL_MAX_HW_QUEUES 32 |
293 | #define IWL_INVALID_STATION 255 | ||
294 | #define IWL_MAX_TID_COUNT 8 | ||
295 | #define IWL_FRAME_LIMIT 64 | ||
293 | 296 | ||
294 | /** | 297 | /** |
295 | * struct iwl_trans_config - transport configuration | 298 | * struct iwl_trans_config - transport configuration |
296 | * | 299 | * |
297 | * @op_mode: pointer to the upper layer. | 300 | * @op_mode: pointer to the upper layer. |
298 | * @queue_to_fifo: queue to FIFO mapping to set up by | ||
299 | * default | ||
300 | * @n_queue_to_fifo: number of queues to set up | ||
301 | * @cmd_queue: the index of the command queue. | 301 | * @cmd_queue: the index of the command queue. |
302 | * Must be set before start_fw. | 302 | * Must be set before start_fw. |
303 | * @cmd_fifo: the fifo for host commands | ||
303 | * @no_reclaim_cmds: Some devices erroneously don't set the | 304 | * @no_reclaim_cmds: Some devices erroneously don't set the |
304 | * SEQ_RX_FRAME bit on some notifications, this is the | 305 | * SEQ_RX_FRAME bit on some notifications, this is the |
305 | * list of such notifications to filter. Max length is | 306 | * list of such notifications to filter. Max length is |
@@ -314,10 +315,9 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) | |||
314 | */ | 315 | */ |
315 | struct iwl_trans_config { | 316 | struct iwl_trans_config { |
316 | struct iwl_op_mode *op_mode; | 317 | struct iwl_op_mode *op_mode; |
317 | const u8 *queue_to_fifo; | ||
318 | u8 n_queue_to_fifo; | ||
319 | 318 | ||
320 | u8 cmd_queue; | 319 | u8 cmd_queue; |
320 | u8 cmd_fifo; | ||
321 | const u8 *no_reclaim_cmds; | 321 | const u8 *no_reclaim_cmds; |
322 | int n_no_reclaim_cmds; | 322 | int n_no_reclaim_cmds; |
323 | 323 | ||
@@ -355,9 +355,9 @@ struct iwl_trans; | |||
355 | * Must be atomic | 355 | * Must be atomic |
356 | * @reclaim: free packet until ssn. Returns a list of freed packets. | 356 | * @reclaim: free packet until ssn. Returns a list of freed packets. |
357 | * Must be atomic | 357 | * Must be atomic |
358 | * @txq_enable: setup a tx queue for AMPDU - will be called once the HW is | 358 | * @txq_enable: setup a queue. To setup an AC queue, use the |
359 | * ready and a successful ADDBA response has been received. | 359 | * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before |
360 | * May sleep | 360 | * this one. The op_mode must not configure the HCMD queue. May sleep. |
361 | * @txq_disable: de-configure a Tx queue to send AMPDUs | 361 | * @txq_disable: de-configure a Tx queue to send AMPDUs |
362 | * Must be atomic | 362 | * Must be atomic |
363 | * @wait_tx_queue_empty: wait until all tx queues are empty | 363 | * @wait_tx_queue_empty: wait until all tx queues are empty |
@@ -497,9 +497,9 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans) | |||
497 | { | 497 | { |
498 | might_sleep(); | 498 | might_sleep(); |
499 | 499 | ||
500 | trans->ops->fw_alive(trans); | ||
501 | |||
502 | trans->state = IWL_TRANS_FW_ALIVE; | 500 | trans->state = IWL_TRANS_FW_ALIVE; |
501 | |||
502 | trans->ops->fw_alive(trans); | ||
503 | } | 503 | } |
504 | 504 | ||
505 | static inline int iwl_trans_start_fw(struct iwl_trans *trans, | 505 | static inline int iwl_trans_start_fw(struct iwl_trans *trans, |
@@ -593,6 +593,13 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | |||
593 | frame_limit, ssn); | 593 | frame_limit, ssn); |
594 | } | 594 | } |
595 | 595 | ||
596 | static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, | ||
597 | int fifo) | ||
598 | { | ||
599 | iwl_trans_txq_enable(trans, queue, fifo, IWL_INVALID_STATION, | ||
600 | IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); | ||
601 | } | ||
602 | |||
596 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) | 603 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) |
597 | { | 604 | { |
598 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 605 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5024fb662bf6..d9694c58208c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -269,10 +269,9 @@ struct iwl_trans_pcie { | |||
269 | wait_queue_head_t ucode_write_waitq; | 269 | wait_queue_head_t ucode_write_waitq; |
270 | unsigned long status; | 270 | unsigned long status; |
271 | u8 cmd_queue; | 271 | u8 cmd_queue; |
272 | u8 cmd_fifo; | ||
272 | u8 n_no_reclaim_cmds; | 273 | u8 n_no_reclaim_cmds; |
273 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; | 274 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; |
274 | u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES]; | ||
275 | u8 n_q_to_fifo; | ||
276 | 275 | ||
277 | bool rx_buf_size_8k; | 276 | bool rx_buf_size_8k; |
278 | u32 rx_page_order; | 277 | u32 rx_page_order; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index be143eb4aa4f..39a6ca1f009c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -879,9 +879,6 @@ static irqreturn_t iwl_isr(int irq, void *data) | |||
879 | 879 | ||
880 | lockdep_assert_held(&trans_pcie->irq_lock); | 880 | lockdep_assert_held(&trans_pcie->irq_lock); |
881 | 881 | ||
882 | if (!trans) | ||
883 | return IRQ_NONE; | ||
884 | |||
885 | trace_iwlwifi_dev_irq(trans->dev); | 882 | trace_iwlwifi_dev_irq(trans->dev); |
886 | 883 | ||
887 | /* Disable (but don't clear!) interrupts here to avoid | 884 | /* Disable (but don't clear!) interrupts here to avoid |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index d1950838f17f..09795afccb23 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -1059,7 +1059,7 @@ static void iwl_tx_start(struct iwl_trans *trans) | |||
1059 | { | 1059 | { |
1060 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1060 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1061 | u32 a; | 1061 | u32 a; |
1062 | int i, chan; | 1062 | int chan; |
1063 | u32 reg_val; | 1063 | u32 reg_val; |
1064 | 1064 | ||
1065 | /* make sure all queue are not stopped/used */ | 1065 | /* make sure all queue are not stopped/used */ |
@@ -1091,12 +1091,8 @@ static void iwl_tx_start(struct iwl_trans *trans) | |||
1091 | */ | 1091 | */ |
1092 | iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); | 1092 | iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); |
1093 | 1093 | ||
1094 | for (i = 0; i < trans_pcie->n_q_to_fifo; i++) { | 1094 | iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, |
1095 | int fifo = trans_pcie->setup_q_to_fifo[i]; | 1095 | trans_pcie->cmd_fifo); |
1096 | |||
1097 | iwl_trans_pcie_txq_enable(trans, i, fifo, IWL_INVALID_STATION, | ||
1098 | IWL_TID_NON_QOS, SCD_FRAME_LIMIT, 0); | ||
1099 | } | ||
1100 | 1096 | ||
1101 | /* Activate all Tx DMA/FIFO channels */ | 1097 | /* Activate all Tx DMA/FIFO channels */ |
1102 | iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); | 1098 | iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); |
@@ -1145,7 +1141,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) | |||
1145 | FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); | 1141 | FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); |
1146 | if (ret < 0) | 1142 | if (ret < 0) |
1147 | IWL_ERR(trans, | 1143 | IWL_ERR(trans, |
1148 | "Failing on timeout while stopping DMA channel %d [0x%08x]", | 1144 | "Failing on timeout while stopping DMA channel %d [0x%08x]\n", |
1149 | ch, | 1145 | ch, |
1150 | iwl_read_direct32(trans, | 1146 | iwl_read_direct32(trans, |
1151 | FH_TSSR_TX_STATUS_REG)); | 1147 | FH_TSSR_TX_STATUS_REG)); |
@@ -1153,7 +1149,8 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) | |||
1153 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); | 1149 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1154 | 1150 | ||
1155 | if (!trans_pcie->txq) { | 1151 | if (!trans_pcie->txq) { |
1156 | IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); | 1152 | IWL_WARN(trans, |
1153 | "Stopping tx queues that aren't allocated...\n"); | ||
1157 | return 0; | 1154 | return 0; |
1158 | } | 1155 | } |
1159 | 1156 | ||
@@ -1430,7 +1427,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) | |||
1430 | 1427 | ||
1431 | err = iwl_prepare_card_hw(trans); | 1428 | err = iwl_prepare_card_hw(trans); |
1432 | if (err) { | 1429 | if (err) { |
1433 | IWL_ERR(trans, "Error while preparing HW: %d", err); | 1430 | IWL_ERR(trans, "Error while preparing HW: %d\n", err); |
1434 | goto err_free_irq; | 1431 | goto err_free_irq; |
1435 | } | 1432 | } |
1436 | 1433 | ||
@@ -1528,6 +1525,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
1528 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1525 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1529 | 1526 | ||
1530 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; | 1527 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; |
1528 | trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; | ||
1531 | if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) | 1529 | if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) |
1532 | trans_pcie->n_no_reclaim_cmds = 0; | 1530 | trans_pcie->n_no_reclaim_cmds = 0; |
1533 | else | 1531 | else |
@@ -1536,17 +1534,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
1536 | memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds, | 1534 | memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds, |
1537 | trans_pcie->n_no_reclaim_cmds * sizeof(u8)); | 1535 | trans_pcie->n_no_reclaim_cmds * sizeof(u8)); |
1538 | 1536 | ||
1539 | trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo; | ||
1540 | |||
1541 | if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES)) | ||
1542 | trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES; | ||
1543 | |||
1544 | /* at least the command queue must be mapped */ | ||
1545 | WARN_ON(!trans_pcie->n_q_to_fifo); | ||
1546 | |||
1547 | memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo, | ||
1548 | trans_pcie->n_q_to_fifo * sizeof(u8)); | ||
1549 | |||
1550 | trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k; | 1537 | trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k; |
1551 | if (trans_pcie->rx_buf_size_8k) | 1538 | if (trans_pcie->rx_buf_size_8k) |
1552 | trans_pcie->rx_page_order = get_order(8 * 1024); | 1539 | trans_pcie->rx_page_order = get_order(8 * 1024); |
@@ -2141,13 +2128,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
2141 | 2128 | ||
2142 | err = pci_request_regions(pdev, DRV_NAME); | 2129 | err = pci_request_regions(pdev, DRV_NAME); |
2143 | if (err) { | 2130 | if (err) { |
2144 | dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed"); | 2131 | dev_printk(KERN_ERR, &pdev->dev, |
2132 | "pci_request_regions failed\n"); | ||
2145 | goto out_pci_disable_device; | 2133 | goto out_pci_disable_device; |
2146 | } | 2134 | } |
2147 | 2135 | ||
2148 | trans_pcie->hw_base = pci_ioremap_bar(pdev, 0); | 2136 | trans_pcie->hw_base = pci_ioremap_bar(pdev, 0); |
2149 | if (!trans_pcie->hw_base) { | 2137 | if (!trans_pcie->hw_base) { |
2150 | dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed"); | 2138 | dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed\n"); |
2151 | err = -ENODEV; | 2139 | err = -ENODEV; |
2152 | goto out_pci_release_regions; | 2140 | goto out_pci_release_regions; |
2153 | } | 2141 | } |
@@ -2168,7 +2156,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
2168 | err = pci_enable_msi(pdev); | 2156 | err = pci_enable_msi(pdev); |
2169 | if (err) | 2157 | if (err) |
2170 | dev_printk(KERN_ERR, &pdev->dev, | 2158 | dev_printk(KERN_ERR, &pdev->dev, |
2171 | "pci_enable_msi failed(0X%x)", err); | 2159 | "pci_enable_msi failed(0X%x)\n", err); |
2172 | 2160 | ||
2173 | trans->dev = &pdev->dev; | 2161 | trans->dev = &pdev->dev; |
2174 | trans_pcie->irq = pdev->irq; | 2162 | trans_pcie->irq = pdev->irq; |
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig deleted file mode 100644 index 7107ce53d4d4..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | config IWM | ||
2 | tristate "Intel Wireless Multicomm 3200 WiFi driver (EXPERIMENTAL)" | ||
3 | depends on MMC && EXPERIMENTAL | ||
4 | depends on CFG80211 | ||
5 | select FW_LOADER | ||
6 | select IWMC3200TOP | ||
7 | help | ||
8 | The Intel Wireless Multicomm 3200 hardware is a combo | ||
9 | card with GPS, Bluetooth, WiMax and 802.11 radios. It | ||
10 | runs over SDIO and is typically found on Moorestown | ||
11 | based platform. This driver takes care of the 802.11 | ||
12 | part, which is a fullmac one. | ||
13 | |||
14 | If you choose to build it as a module, it'll be called | ||
15 | iwmc3200wifi.ko. | ||
16 | |||
17 | config IWM_DEBUG | ||
18 | bool "Enable full debugging output in iwmc3200wifi" | ||
19 | depends on IWM && DEBUG_FS | ||
20 | help | ||
21 | This option will enable debug tracing and setting for iwm | ||
22 | |||
23 | You can set the debug level and module through debugfs. By | ||
24 | default all modules are set to the IWL_DL_ERR level. | ||
25 | To see the list of debug modules and levels, see iwm/debug.h | ||
26 | |||
27 | For example, if you want the full MLME debug output: | ||
28 | echo 0xff > /sys/kernel/debug/iwm/phyN/debug/mlme | ||
29 | |||
30 | Or, if you want the full debug, for all modules: | ||
31 | echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level | ||
32 | echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules | ||
33 | |||
34 | config IWM_TRACING | ||
35 | bool "Enable event tracing for iwmc3200wifi" | ||
36 | depends on IWM && EVENT_TRACING | ||
37 | help | ||
38 | Say Y here to trace all the commands and responses between | ||
39 | the driver and firmware (including TX/RX frames) with ftrace. | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile deleted file mode 100644 index cdc7e07ba113..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | obj-$(CONFIG_IWM) := iwmc3200wifi.o | ||
2 | iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o | ||
3 | iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o | ||
4 | |||
5 | iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o | ||
6 | iwmc3200wifi-$(CONFIG_IWM_TRACING) += trace.o | ||
7 | |||
8 | CFLAGS_trace.o := -I$(src) | ||
9 | |||
10 | ccflags-y += -D__CHECK_ENDIAN__ | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h deleted file mode 100644 index 62edd5888a7b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/bus.h +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_BUS_H__ | ||
25 | #define __IWM_BUS_H__ | ||
26 | |||
27 | #include "iwm.h" | ||
28 | |||
29 | struct iwm_if_ops { | ||
30 | int (*enable)(struct iwm_priv *iwm); | ||
31 | int (*disable)(struct iwm_priv *iwm); | ||
32 | int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count); | ||
33 | |||
34 | void (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir); | ||
35 | void (*debugfs_exit)(struct iwm_priv *iwm); | ||
36 | |||
37 | const char *umac_name; | ||
38 | const char *calib_lmac_name; | ||
39 | const char *lmac_name; | ||
40 | }; | ||
41 | |||
42 | static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) | ||
43 | { | ||
44 | return iwm->bus_ops->send_chunk(iwm, buf, count); | ||
45 | } | ||
46 | |||
47 | static inline int iwm_bus_enable(struct iwm_priv *iwm) | ||
48 | { | ||
49 | return iwm->bus_ops->enable(iwm); | ||
50 | } | ||
51 | |||
52 | static inline int iwm_bus_disable(struct iwm_priv *iwm) | ||
53 | { | ||
54 | return iwm->bus_ops->disable(iwm); | ||
55 | } | ||
56 | |||
57 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c deleted file mode 100644 index 48e8218fd23b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ /dev/null | |||
@@ -1,882 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/wireless.h> | ||
29 | #include <linux/ieee80211.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <net/cfg80211.h> | ||
32 | |||
33 | #include "iwm.h" | ||
34 | #include "commands.h" | ||
35 | #include "cfg80211.h" | ||
36 | #include "debug.h" | ||
37 | |||
38 | #define RATETAB_ENT(_rate, _rateid, _flags) \ | ||
39 | { \ | ||
40 | .bitrate = (_rate), \ | ||
41 | .hw_value = (_rateid), \ | ||
42 | .flags = (_flags), \ | ||
43 | } | ||
44 | |||
45 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
46 | .band = IEEE80211_BAND_2GHZ, \ | ||
47 | .center_freq = (_freq), \ | ||
48 | .hw_value = (_channel), \ | ||
49 | .flags = (_flags), \ | ||
50 | .max_antenna_gain = 0, \ | ||
51 | .max_power = 30, \ | ||
52 | } | ||
53 | |||
54 | #define CHAN5G(_channel, _flags) { \ | ||
55 | .band = IEEE80211_BAND_5GHZ, \ | ||
56 | .center_freq = 5000 + (5 * (_channel)), \ | ||
57 | .hw_value = (_channel), \ | ||
58 | .flags = (_flags), \ | ||
59 | .max_antenna_gain = 0, \ | ||
60 | .max_power = 30, \ | ||
61 | } | ||
62 | |||
63 | static struct ieee80211_rate iwm_rates[] = { | ||
64 | RATETAB_ENT(10, 0x1, 0), | ||
65 | RATETAB_ENT(20, 0x2, 0), | ||
66 | RATETAB_ENT(55, 0x4, 0), | ||
67 | RATETAB_ENT(110, 0x8, 0), | ||
68 | RATETAB_ENT(60, 0x10, 0), | ||
69 | RATETAB_ENT(90, 0x20, 0), | ||
70 | RATETAB_ENT(120, 0x40, 0), | ||
71 | RATETAB_ENT(180, 0x80, 0), | ||
72 | RATETAB_ENT(240, 0x100, 0), | ||
73 | RATETAB_ENT(360, 0x200, 0), | ||
74 | RATETAB_ENT(480, 0x400, 0), | ||
75 | RATETAB_ENT(540, 0x800, 0), | ||
76 | }; | ||
77 | |||
78 | #define iwm_a_rates (iwm_rates + 4) | ||
79 | #define iwm_a_rates_size 8 | ||
80 | #define iwm_g_rates (iwm_rates + 0) | ||
81 | #define iwm_g_rates_size 12 | ||
82 | |||
83 | static struct ieee80211_channel iwm_2ghz_channels[] = { | ||
84 | CHAN2G(1, 2412, 0), | ||
85 | CHAN2G(2, 2417, 0), | ||
86 | CHAN2G(3, 2422, 0), | ||
87 | CHAN2G(4, 2427, 0), | ||
88 | CHAN2G(5, 2432, 0), | ||
89 | CHAN2G(6, 2437, 0), | ||
90 | CHAN2G(7, 2442, 0), | ||
91 | CHAN2G(8, 2447, 0), | ||
92 | CHAN2G(9, 2452, 0), | ||
93 | CHAN2G(10, 2457, 0), | ||
94 | CHAN2G(11, 2462, 0), | ||
95 | CHAN2G(12, 2467, 0), | ||
96 | CHAN2G(13, 2472, 0), | ||
97 | CHAN2G(14, 2484, 0), | ||
98 | }; | ||
99 | |||
100 | static struct ieee80211_channel iwm_5ghz_a_channels[] = { | ||
101 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
102 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
103 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
104 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
105 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
106 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
107 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
108 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
109 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
110 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
111 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
112 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
113 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
114 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
115 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
116 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
117 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
118 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
119 | CHAN5G(216, 0), | ||
120 | }; | ||
121 | |||
122 | static struct ieee80211_supported_band iwm_band_2ghz = { | ||
123 | .channels = iwm_2ghz_channels, | ||
124 | .n_channels = ARRAY_SIZE(iwm_2ghz_channels), | ||
125 | .bitrates = iwm_g_rates, | ||
126 | .n_bitrates = iwm_g_rates_size, | ||
127 | }; | ||
128 | |||
129 | static struct ieee80211_supported_band iwm_band_5ghz = { | ||
130 | .channels = iwm_5ghz_a_channels, | ||
131 | .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels), | ||
132 | .bitrates = iwm_a_rates, | ||
133 | .n_bitrates = iwm_a_rates_size, | ||
134 | }; | ||
135 | |||
136 | static int iwm_key_init(struct iwm_key *key, u8 key_index, | ||
137 | const u8 *mac_addr, struct key_params *params) | ||
138 | { | ||
139 | key->hdr.key_idx = key_index; | ||
140 | if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { | ||
141 | key->hdr.multicast = 1; | ||
142 | memset(key->hdr.mac, 0xff, ETH_ALEN); | ||
143 | } else { | ||
144 | key->hdr.multicast = 0; | ||
145 | memcpy(key->hdr.mac, mac_addr, ETH_ALEN); | ||
146 | } | ||
147 | |||
148 | if (params) { | ||
149 | if (params->key_len > WLAN_MAX_KEY_LEN || | ||
150 | params->seq_len > IW_ENCODE_SEQ_MAX_SIZE) | ||
151 | return -EINVAL; | ||
152 | |||
153 | key->cipher = params->cipher; | ||
154 | key->key_len = params->key_len; | ||
155 | key->seq_len = params->seq_len; | ||
156 | memcpy(key->key, params->key, key->key_len); | ||
157 | memcpy(key->seq, params->seq, key->seq_len); | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | ||
164 | u8 key_index, bool pairwise, const u8 *mac_addr, | ||
165 | struct key_params *params) | ||
166 | { | ||
167 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
168 | struct iwm_key *key; | ||
169 | int ret; | ||
170 | |||
171 | IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr); | ||
172 | |||
173 | if (key_index >= IWM_NUM_KEYS) | ||
174 | return -ENOENT; | ||
175 | |||
176 | key = &iwm->keys[key_index]; | ||
177 | memset(key, 0, sizeof(struct iwm_key)); | ||
178 | ret = iwm_key_init(key, key_index, mac_addr, params); | ||
179 | if (ret < 0) { | ||
180 | IWM_ERR(iwm, "Invalid key_params\n"); | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | return iwm_set_key(iwm, 0, key); | ||
185 | } | ||
186 | |||
187 | static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, | ||
188 | u8 key_index, bool pairwise, const u8 *mac_addr, | ||
189 | void *cookie, | ||
190 | void (*callback)(void *cookie, | ||
191 | struct key_params*)) | ||
192 | { | ||
193 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
194 | struct iwm_key *key; | ||
195 | struct key_params params; | ||
196 | |||
197 | IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); | ||
198 | |||
199 | if (key_index >= IWM_NUM_KEYS) | ||
200 | return -ENOENT; | ||
201 | |||
202 | memset(¶ms, 0, sizeof(params)); | ||
203 | |||
204 | key = &iwm->keys[key_index]; | ||
205 | params.cipher = key->cipher; | ||
206 | params.key_len = key->key_len; | ||
207 | params.seq_len = key->seq_len; | ||
208 | params.seq = key->seq; | ||
209 | params.key = key->key; | ||
210 | |||
211 | callback(cookie, ¶ms); | ||
212 | |||
213 | return key->key_len ? 0 : -ENOENT; | ||
214 | } | ||
215 | |||
216 | |||
217 | static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, | ||
218 | u8 key_index, bool pairwise, const u8 *mac_addr) | ||
219 | { | ||
220 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
221 | struct iwm_key *key; | ||
222 | |||
223 | if (key_index >= IWM_NUM_KEYS) | ||
224 | return -ENOENT; | ||
225 | |||
226 | key = &iwm->keys[key_index]; | ||
227 | if (!iwm->keys[key_index].key_len) { | ||
228 | IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | if (key_index == iwm->default_key) | ||
233 | iwm->default_key = -1; | ||
234 | |||
235 | return iwm_set_key(iwm, 1, key); | ||
236 | } | ||
237 | |||
238 | static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, | ||
239 | struct net_device *ndev, | ||
240 | u8 key_index, bool unicast, | ||
241 | bool multicast) | ||
242 | { | ||
243 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
244 | |||
245 | IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); | ||
246 | |||
247 | if (key_index >= IWM_NUM_KEYS) | ||
248 | return -ENOENT; | ||
249 | |||
250 | if (!iwm->keys[key_index].key_len) { | ||
251 | IWM_ERR(iwm, "Key %d not used\n", key_index); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | iwm->default_key = key_index; | ||
256 | |||
257 | return iwm_set_tx_key(iwm, key_index); | ||
258 | } | ||
259 | |||
260 | static int iwm_cfg80211_get_station(struct wiphy *wiphy, | ||
261 | struct net_device *ndev, | ||
262 | u8 *mac, struct station_info *sinfo) | ||
263 | { | ||
264 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
265 | |||
266 | if (memcmp(mac, iwm->bssid, ETH_ALEN)) | ||
267 | return -ENOENT; | ||
268 | |||
269 | sinfo->filled |= STATION_INFO_TX_BITRATE; | ||
270 | sinfo->txrate.legacy = iwm->rate * 10; | ||
271 | |||
272 | if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
273 | sinfo->filled |= STATION_INFO_SIGNAL; | ||
274 | sinfo->signal = iwm->wstats.qual.level; | ||
275 | } | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | |||
281 | int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) | ||
282 | { | ||
283 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
284 | struct iwm_bss_info *bss; | ||
285 | struct iwm_umac_notif_bss_info *umac_bss; | ||
286 | struct ieee80211_mgmt *mgmt; | ||
287 | struct ieee80211_channel *channel; | ||
288 | struct ieee80211_supported_band *band; | ||
289 | s32 signal; | ||
290 | int freq; | ||
291 | |||
292 | list_for_each_entry(bss, &iwm->bss_list, node) { | ||
293 | umac_bss = bss->bss; | ||
294 | mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); | ||
295 | |||
296 | if (umac_bss->band == UMAC_BAND_2GHZ) | ||
297 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
298 | else if (umac_bss->band == UMAC_BAND_5GHZ) | ||
299 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
300 | else { | ||
301 | IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | freq = ieee80211_channel_to_frequency(umac_bss->channel, | ||
306 | band->band); | ||
307 | channel = ieee80211_get_channel(wiphy, freq); | ||
308 | signal = umac_bss->rssi * 100; | ||
309 | |||
310 | if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt, | ||
311 | le16_to_cpu(umac_bss->frame_len), | ||
312 | signal, GFP_KERNEL)) | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int iwm_cfg80211_change_iface(struct wiphy *wiphy, | ||
320 | struct net_device *ndev, | ||
321 | enum nl80211_iftype type, u32 *flags, | ||
322 | struct vif_params *params) | ||
323 | { | ||
324 | struct wireless_dev *wdev; | ||
325 | struct iwm_priv *iwm; | ||
326 | u32 old_mode; | ||
327 | |||
328 | wdev = ndev->ieee80211_ptr; | ||
329 | iwm = ndev_to_iwm(ndev); | ||
330 | old_mode = iwm->conf.mode; | ||
331 | |||
332 | switch (type) { | ||
333 | case NL80211_IFTYPE_STATION: | ||
334 | iwm->conf.mode = UMAC_MODE_BSS; | ||
335 | break; | ||
336 | case NL80211_IFTYPE_ADHOC: | ||
337 | iwm->conf.mode = UMAC_MODE_IBSS; | ||
338 | break; | ||
339 | default: | ||
340 | return -EOPNOTSUPP; | ||
341 | } | ||
342 | |||
343 | wdev->iftype = type; | ||
344 | |||
345 | if ((old_mode == iwm->conf.mode) || !iwm->umac_profile) | ||
346 | return 0; | ||
347 | |||
348 | iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); | ||
349 | |||
350 | if (iwm->umac_profile_active) | ||
351 | iwm_invalidate_mlme_profile(iwm); | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
357 | struct cfg80211_scan_request *request) | ||
358 | { | ||
359 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
360 | int ret; | ||
361 | |||
362 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) { | ||
363 | IWM_ERR(iwm, "Scan while device is not ready\n"); | ||
364 | return -EIO; | ||
365 | } | ||
366 | |||
367 | if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) { | ||
368 | IWM_ERR(iwm, "Scanning already\n"); | ||
369 | return -EAGAIN; | ||
370 | } | ||
371 | |||
372 | if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) { | ||
373 | IWM_ERR(iwm, "Scanning being aborted\n"); | ||
374 | return -EAGAIN; | ||
375 | } | ||
376 | |||
377 | set_bit(IWM_STATUS_SCANNING, &iwm->status); | ||
378 | |||
379 | ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids); | ||
380 | if (ret) { | ||
381 | clear_bit(IWM_STATUS_SCANNING, &iwm->status); | ||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | iwm->scan_request = request; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
390 | { | ||
391 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
392 | |||
393 | if (changed & WIPHY_PARAM_RTS_THRESHOLD && | ||
394 | (iwm->conf.rts_threshold != wiphy->rts_threshold)) { | ||
395 | int ret; | ||
396 | |||
397 | iwm->conf.rts_threshold = wiphy->rts_threshold; | ||
398 | |||
399 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
400 | CFG_RTS_THRESHOLD, | ||
401 | iwm->conf.rts_threshold); | ||
402 | if (ret < 0) | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD && | ||
407 | (iwm->conf.frag_threshold != wiphy->frag_threshold)) { | ||
408 | int ret; | ||
409 | |||
410 | iwm->conf.frag_threshold = wiphy->frag_threshold; | ||
411 | |||
412 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, | ||
413 | CFG_FRAG_THRESHOLD, | ||
414 | iwm->conf.frag_threshold); | ||
415 | if (ret < 0) | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
423 | struct cfg80211_ibss_params *params) | ||
424 | { | ||
425 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
426 | struct ieee80211_channel *chan = params->channel; | ||
427 | |||
428 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
429 | return -EIO; | ||
430 | |||
431 | /* UMAC doesn't support creating or joining an IBSS network | ||
432 | * with specified bssid. */ | ||
433 | if (params->bssid) | ||
434 | return -EOPNOTSUPP; | ||
435 | |||
436 | iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); | ||
437 | iwm->umac_profile->ibss.band = chan->band; | ||
438 | iwm->umac_profile->ibss.channel = iwm->channel; | ||
439 | iwm->umac_profile->ssid.ssid_len = params->ssid_len; | ||
440 | memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); | ||
441 | |||
442 | return iwm_send_mlme_profile(iwm); | ||
443 | } | ||
444 | |||
445 | static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
446 | { | ||
447 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
448 | |||
449 | if (iwm->umac_profile_active) | ||
450 | return iwm_invalidate_mlme_profile(iwm); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int iwm_set_auth_type(struct iwm_priv *iwm, | ||
456 | enum nl80211_auth_type sme_auth_type) | ||
457 | { | ||
458 | u8 *auth_type = &iwm->umac_profile->sec.auth_type; | ||
459 | |||
460 | switch (sme_auth_type) { | ||
461 | case NL80211_AUTHTYPE_AUTOMATIC: | ||
462 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
463 | IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n"); | ||
464 | *auth_type = UMAC_AUTH_TYPE_OPEN; | ||
465 | break; | ||
466 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
467 | if (iwm->umac_profile->sec.flags & | ||
468 | (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { | ||
469 | IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n"); | ||
470 | *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; | ||
471 | } else { | ||
472 | IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n"); | ||
473 | *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
474 | } | ||
475 | |||
476 | break; | ||
477 | default: | ||
478 | IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type); | ||
479 | return -ENOTSUPP; | ||
480 | } | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) | ||
486 | { | ||
487 | IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version); | ||
488 | |||
489 | if (!wpa_version) { | ||
490 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | if (wpa_version & NL80211_WPA_VERSION_1) | ||
495 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; | ||
496 | |||
497 | if (wpa_version & NL80211_WPA_VERSION_2) | ||
498 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) | ||
504 | { | ||
505 | u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : | ||
506 | &iwm->umac_profile->sec.mcast_cipher; | ||
507 | |||
508 | if (!cipher) { | ||
509 | *profile_cipher = UMAC_CIPHER_TYPE_NONE; | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm', | ||
514 | cipher); | ||
515 | |||
516 | switch (cipher) { | ||
517 | case IW_AUTH_CIPHER_NONE: | ||
518 | *profile_cipher = UMAC_CIPHER_TYPE_NONE; | ||
519 | break; | ||
520 | case WLAN_CIPHER_SUITE_WEP40: | ||
521 | *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; | ||
522 | break; | ||
523 | case WLAN_CIPHER_SUITE_WEP104: | ||
524 | *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; | ||
525 | break; | ||
526 | case WLAN_CIPHER_SUITE_TKIP: | ||
527 | *profile_cipher = UMAC_CIPHER_TYPE_TKIP; | ||
528 | break; | ||
529 | case WLAN_CIPHER_SUITE_CCMP: | ||
530 | *profile_cipher = UMAC_CIPHER_TYPE_CCMP; | ||
531 | break; | ||
532 | default: | ||
533 | IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); | ||
534 | return -ENOTSUPP; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt) | ||
541 | { | ||
542 | u8 *auth_type = &iwm->umac_profile->sec.auth_type; | ||
543 | |||
544 | IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); | ||
545 | |||
546 | if (key_mgt == WLAN_AKM_SUITE_8021X) | ||
547 | *auth_type = UMAC_AUTH_TYPE_8021X; | ||
548 | else if (key_mgt == WLAN_AKM_SUITE_PSK) { | ||
549 | if (iwm->umac_profile->sec.flags & | ||
550 | (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) | ||
551 | *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; | ||
552 | else | ||
553 | *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
554 | } else { | ||
555 | IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); | ||
556 | return -EINVAL; | ||
557 | } | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | |||
563 | static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | ||
564 | struct cfg80211_connect_params *sme) | ||
565 | { | ||
566 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
567 | struct ieee80211_channel *chan = sme->channel; | ||
568 | struct key_params key_param; | ||
569 | int ret; | ||
570 | |||
571 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
572 | return -EIO; | ||
573 | |||
574 | if (!sme->ssid) | ||
575 | return -EINVAL; | ||
576 | |||
577 | if (iwm->umac_profile_active) { | ||
578 | ret = iwm_invalidate_mlme_profile(iwm); | ||
579 | if (ret) { | ||
580 | IWM_ERR(iwm, "Couldn't invalidate profile\n"); | ||
581 | return ret; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | if (chan) | ||
586 | iwm->channel = | ||
587 | ieee80211_frequency_to_channel(chan->center_freq); | ||
588 | |||
589 | iwm->umac_profile->ssid.ssid_len = sme->ssid_len; | ||
590 | memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len); | ||
591 | |||
592 | if (sme->bssid) { | ||
593 | IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid); | ||
594 | memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN); | ||
595 | iwm->umac_profile->bss_num = 1; | ||
596 | } else { | ||
597 | memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); | ||
598 | iwm->umac_profile->bss_num = 0; | ||
599 | } | ||
600 | |||
601 | ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); | ||
602 | if (ret < 0) | ||
603 | return ret; | ||
604 | |||
605 | ret = iwm_set_auth_type(iwm, sme->auth_type); | ||
606 | if (ret < 0) | ||
607 | return ret; | ||
608 | |||
609 | if (sme->crypto.n_ciphers_pairwise) { | ||
610 | ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0], | ||
611 | true); | ||
612 | if (ret < 0) | ||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false); | ||
617 | if (ret < 0) | ||
618 | return ret; | ||
619 | |||
620 | if (sme->crypto.n_akm_suites) { | ||
621 | ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]); | ||
622 | if (ret < 0) | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * We save the WEP key in case we want to do shared authentication. | ||
628 | * We have to do it so because UMAC will assert whenever it gets a | ||
629 | * key before a profile. | ||
630 | */ | ||
631 | if (sme->key) { | ||
632 | key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL); | ||
633 | if (key_param.key == NULL) | ||
634 | return -ENOMEM; | ||
635 | key_param.key_len = sme->key_len; | ||
636 | key_param.seq_len = 0; | ||
637 | key_param.cipher = sme->crypto.ciphers_pairwise[0]; | ||
638 | |||
639 | ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx, | ||
640 | NULL, &key_param); | ||
641 | kfree(key_param.key); | ||
642 | if (ret < 0) { | ||
643 | IWM_ERR(iwm, "Invalid key_params\n"); | ||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | iwm->default_key = sme->key_idx; | ||
648 | } | ||
649 | |||
650 | /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */ | ||
651 | if ((iwm->umac_profile->sec.flags & | ||
652 | (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) && | ||
653 | iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) { | ||
654 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK; | ||
655 | } | ||
656 | |||
657 | ret = iwm_send_mlme_profile(iwm); | ||
658 | |||
659 | if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || | ||
660 | sme->key == NULL) | ||
661 | return ret; | ||
662 | |||
663 | /* | ||
664 | * We want to do shared auth. | ||
665 | * We need to actually set the key we previously cached, | ||
666 | * and then tell the UMAC it's the default one. | ||
667 | * That will trigger the auth+assoc UMAC machinery, and again, | ||
668 | * this must be done after setting the profile. | ||
669 | */ | ||
670 | ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]); | ||
671 | if (ret < 0) | ||
672 | return ret; | ||
673 | |||
674 | return iwm_set_tx_key(iwm, iwm->default_key); | ||
675 | } | ||
676 | |||
677 | static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, | ||
678 | u16 reason_code) | ||
679 | { | ||
680 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
681 | |||
682 | IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); | ||
683 | |||
684 | if (iwm->umac_profile_active) | ||
685 | iwm_invalidate_mlme_profile(iwm); | ||
686 | |||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, | ||
691 | enum nl80211_tx_power_setting type, int mbm) | ||
692 | { | ||
693 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
694 | int ret; | ||
695 | |||
696 | switch (type) { | ||
697 | case NL80211_TX_POWER_AUTOMATIC: | ||
698 | return 0; | ||
699 | case NL80211_TX_POWER_FIXED: | ||
700 | if (mbm < 0 || (mbm % 100)) | ||
701 | return -EOPNOTSUPP; | ||
702 | |||
703 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
704 | return 0; | ||
705 | |||
706 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
707 | CFG_TX_PWR_LIMIT_USR, | ||
708 | MBM_TO_DBM(mbm) * 2); | ||
709 | if (ret < 0) | ||
710 | return ret; | ||
711 | |||
712 | return iwm_tx_power_trigger(iwm); | ||
713 | default: | ||
714 | IWM_ERR(iwm, "Unsupported power type: %d\n", type); | ||
715 | return -EOPNOTSUPP; | ||
716 | } | ||
717 | |||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) | ||
722 | { | ||
723 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
724 | |||
725 | *dbm = iwm->txpower >> 1; | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, | ||
731 | struct net_device *dev, | ||
732 | bool enabled, int timeout) | ||
733 | { | ||
734 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
735 | u32 power_index; | ||
736 | |||
737 | if (enabled) | ||
738 | power_index = IWM_POWER_INDEX_DEFAULT; | ||
739 | else | ||
740 | power_index = IWM_POWER_INDEX_MIN; | ||
741 | |||
742 | if (power_index == iwm->conf.power_index) | ||
743 | return 0; | ||
744 | |||
745 | iwm->conf.power_index = power_index; | ||
746 | |||
747 | return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
748 | CFG_POWER_INDEX, iwm->conf.power_index); | ||
749 | } | ||
750 | |||
751 | static int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, | ||
752 | struct net_device *netdev, | ||
753 | struct cfg80211_pmksa *pmksa) | ||
754 | { | ||
755 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
756 | |||
757 | return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD); | ||
758 | } | ||
759 | |||
760 | static int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, | ||
761 | struct net_device *netdev, | ||
762 | struct cfg80211_pmksa *pmksa) | ||
763 | { | ||
764 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
765 | |||
766 | return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL); | ||
767 | } | ||
768 | |||
769 | static int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, | ||
770 | struct net_device *netdev) | ||
771 | { | ||
772 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
773 | struct cfg80211_pmksa pmksa; | ||
774 | |||
775 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); | ||
776 | |||
777 | return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH); | ||
778 | } | ||
779 | |||
780 | |||
781 | static struct cfg80211_ops iwm_cfg80211_ops = { | ||
782 | .change_virtual_intf = iwm_cfg80211_change_iface, | ||
783 | .add_key = iwm_cfg80211_add_key, | ||
784 | .get_key = iwm_cfg80211_get_key, | ||
785 | .del_key = iwm_cfg80211_del_key, | ||
786 | .set_default_key = iwm_cfg80211_set_default_key, | ||
787 | .get_station = iwm_cfg80211_get_station, | ||
788 | .scan = iwm_cfg80211_scan, | ||
789 | .set_wiphy_params = iwm_cfg80211_set_wiphy_params, | ||
790 | .connect = iwm_cfg80211_connect, | ||
791 | .disconnect = iwm_cfg80211_disconnect, | ||
792 | .join_ibss = iwm_cfg80211_join_ibss, | ||
793 | .leave_ibss = iwm_cfg80211_leave_ibss, | ||
794 | .set_tx_power = iwm_cfg80211_set_txpower, | ||
795 | .get_tx_power = iwm_cfg80211_get_txpower, | ||
796 | .set_power_mgmt = iwm_cfg80211_set_power_mgmt, | ||
797 | .set_pmksa = iwm_cfg80211_set_pmksa, | ||
798 | .del_pmksa = iwm_cfg80211_del_pmksa, | ||
799 | .flush_pmksa = iwm_cfg80211_flush_pmksa, | ||
800 | }; | ||
801 | |||
802 | static const u32 cipher_suites[] = { | ||
803 | WLAN_CIPHER_SUITE_WEP40, | ||
804 | WLAN_CIPHER_SUITE_WEP104, | ||
805 | WLAN_CIPHER_SUITE_TKIP, | ||
806 | WLAN_CIPHER_SUITE_CCMP, | ||
807 | }; | ||
808 | |||
809 | struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) | ||
810 | { | ||
811 | int ret = 0; | ||
812 | struct wireless_dev *wdev; | ||
813 | |||
814 | /* | ||
815 | * We're trying to have the following memory | ||
816 | * layout: | ||
817 | * | ||
818 | * +-------------------------+ | ||
819 | * | struct wiphy | | ||
820 | * +-------------------------+ | ||
821 | * | struct iwm_priv | | ||
822 | * +-------------------------+ | ||
823 | * | bus private data | | ||
824 | * | (e.g. iwm_priv_sdio) | | ||
825 | * +-------------------------+ | ||
826 | * | ||
827 | */ | ||
828 | |||
829 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
830 | if (!wdev) { | ||
831 | dev_err(dev, "Couldn't allocate wireless device\n"); | ||
832 | return ERR_PTR(-ENOMEM); | ||
833 | } | ||
834 | |||
835 | wdev->wiphy = wiphy_new(&iwm_cfg80211_ops, | ||
836 | sizeof(struct iwm_priv) + sizeof_bus); | ||
837 | if (!wdev->wiphy) { | ||
838 | dev_err(dev, "Couldn't allocate wiphy device\n"); | ||
839 | ret = -ENOMEM; | ||
840 | goto out_err_new; | ||
841 | } | ||
842 | |||
843 | set_wiphy_dev(wdev->wiphy, dev); | ||
844 | wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; | ||
845 | wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS; | ||
846 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
847 | BIT(NL80211_IFTYPE_ADHOC); | ||
848 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; | ||
849 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; | ||
850 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
851 | |||
852 | wdev->wiphy->cipher_suites = cipher_suites; | ||
853 | wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); | ||
854 | |||
855 | ret = wiphy_register(wdev->wiphy); | ||
856 | if (ret < 0) { | ||
857 | dev_err(dev, "Couldn't register wiphy device\n"); | ||
858 | goto out_err_register; | ||
859 | } | ||
860 | |||
861 | return wdev; | ||
862 | |||
863 | out_err_register: | ||
864 | wiphy_free(wdev->wiphy); | ||
865 | |||
866 | out_err_new: | ||
867 | kfree(wdev); | ||
868 | |||
869 | return ERR_PTR(ret); | ||
870 | } | ||
871 | |||
872 | void iwm_wdev_free(struct iwm_priv *iwm) | ||
873 | { | ||
874 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
875 | |||
876 | if (!wdev) | ||
877 | return; | ||
878 | |||
879 | wiphy_unregister(wdev->wiphy); | ||
880 | wiphy_free(wdev->wiphy); | ||
881 | kfree(wdev); | ||
882 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h deleted file mode 100644 index 56a34145acbf..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_CFG80211_H__ | ||
25 | #define __IWM_CFG80211_H__ | ||
26 | |||
27 | int iwm_cfg80211_inform_bss(struct iwm_priv *iwm); | ||
28 | struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev); | ||
29 | void iwm_wdev_free(struct iwm_priv *iwm); | ||
30 | |||
31 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c deleted file mode 100644 index bd75078c454b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ /dev/null | |||
@@ -1,1002 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/wireless.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/ieee80211.h> | ||
43 | #include <linux/sched.h> | ||
44 | #include <linux/slab.h> | ||
45 | #include <linux/moduleparam.h> | ||
46 | |||
47 | #include "iwm.h" | ||
48 | #include "bus.h" | ||
49 | #include "hal.h" | ||
50 | #include "umac.h" | ||
51 | #include "commands.h" | ||
52 | #include "debug.h" | ||
53 | |||
54 | static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, | ||
55 | u8 lmac_cmd_id, | ||
56 | const void *lmac_payload, | ||
57 | u16 lmac_payload_size, | ||
58 | u8 resp) | ||
59 | { | ||
60 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; | ||
61 | struct iwm_umac_cmd umac_cmd; | ||
62 | struct iwm_lmac_cmd lmac_cmd; | ||
63 | |||
64 | lmac_cmd.id = lmac_cmd_id; | ||
65 | |||
66 | umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; | ||
67 | umac_cmd.resp = resp; | ||
68 | |||
69 | return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, | ||
70 | lmac_payload, lmac_payload_size); | ||
71 | } | ||
72 | |||
73 | int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, | ||
74 | bool resp) | ||
75 | { | ||
76 | struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; | ||
77 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
78 | struct iwm_umac_cmd umac_cmd; | ||
79 | int ret; | ||
80 | u8 oid = hdr->oid; | ||
81 | |||
82 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) { | ||
83 | IWM_ERR(iwm, "Interface is not ready yet"); | ||
84 | return -EAGAIN; | ||
85 | } | ||
86 | |||
87 | umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; | ||
88 | umac_cmd.resp = resp; | ||
89 | |||
90 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, | ||
91 | payload, payload_size); | ||
92 | |||
93 | if (resp) { | ||
94 | ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, | ||
95 | test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), | ||
96 | 3 * HZ); | ||
97 | |||
98 | return ret ? 0 : -EBUSY; | ||
99 | } | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static int modparam_wiwi = COEX_MODE_CM; | ||
105 | module_param_named(wiwi, modparam_wiwi, int, 0644); | ||
106 | MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); | ||
107 | |||
108 | static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = | ||
109 | { | ||
110 | {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, | ||
111 | {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, | ||
112 | {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, | ||
113 | {4, 3, 0, COEX_CALIBRATION_FLAGS}, | ||
114 | {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, | ||
115 | {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, | ||
116 | {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, | ||
117 | {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, | ||
118 | {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, | ||
119 | {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, | ||
120 | {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, | ||
121 | {4, 3, 0, COEX_RF_OFF_FLAGS}, | ||
122 | {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, | ||
123 | {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, | ||
124 | {4, 3, 0, COEX_RSRVD1_FLAGS}, | ||
125 | {4, 3, 0, COEX_RSRVD2_FLAGS} | ||
126 | }; | ||
127 | |||
128 | static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = | ||
129 | { | ||
130 | {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, | ||
131 | {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, | ||
132 | {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, | ||
133 | {6, 6, 0, COEX_CALIBRATION_FLAGS}, | ||
134 | {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, | ||
135 | {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS}, | ||
136 | {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, | ||
137 | {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, | ||
138 | {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, | ||
139 | {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, | ||
140 | {1, 1, 0, COEX_RF_ON_FLAGS}, | ||
141 | {1, 1, 0, COEX_RF_OFF_FLAGS}, | ||
142 | {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, | ||
143 | {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, | ||
144 | {1, 1, 0, COEX_RSRVD1_FLAGS}, | ||
145 | {1, 1, 0, COEX_RSRVD2_FLAGS} | ||
146 | }; | ||
147 | |||
148 | int iwm_send_prio_table(struct iwm_priv *iwm) | ||
149 | { | ||
150 | struct iwm_coex_prio_table_cmd coex_table_cmd; | ||
151 | u32 coex_enabled, mode_enabled; | ||
152 | |||
153 | memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); | ||
154 | |||
155 | coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; | ||
156 | |||
157 | switch (modparam_wiwi) { | ||
158 | case COEX_MODE_XOR: | ||
159 | case COEX_MODE_CM: | ||
160 | coex_enabled = 1; | ||
161 | break; | ||
162 | default: | ||
163 | coex_enabled = 0; | ||
164 | break; | ||
165 | } | ||
166 | |||
167 | switch (iwm->conf.mode) { | ||
168 | case UMAC_MODE_BSS: | ||
169 | case UMAC_MODE_IBSS: | ||
170 | mode_enabled = 1; | ||
171 | break; | ||
172 | default: | ||
173 | mode_enabled = 0; | ||
174 | break; | ||
175 | } | ||
176 | |||
177 | if (coex_enabled && mode_enabled) { | ||
178 | coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | | ||
179 | COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | | ||
180 | COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; | ||
181 | |||
182 | switch (modparam_wiwi) { | ||
183 | case COEX_MODE_XOR: | ||
184 | memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, | ||
185 | sizeof(iwm_sta_xor_prio_tbl)); | ||
186 | break; | ||
187 | case COEX_MODE_CM: | ||
188 | memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, | ||
189 | sizeof(iwm_sta_cm_prio_tbl)); | ||
190 | break; | ||
191 | default: | ||
192 | IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", | ||
193 | modparam_wiwi); | ||
194 | break; | ||
195 | } | ||
196 | } else | ||
197 | IWM_WARN(iwm, "coexistense disabled\n"); | ||
198 | |||
199 | return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, | ||
200 | &coex_table_cmd, | ||
201 | sizeof(struct iwm_coex_prio_table_cmd), 0); | ||
202 | } | ||
203 | |||
204 | int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) | ||
205 | { | ||
206 | struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; | ||
207 | |||
208 | memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); | ||
209 | |||
210 | cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); | ||
211 | cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); | ||
212 | cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); | ||
213 | cal_cfg_cmd.ucode_cfg.flags = | ||
214 | cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); | ||
215 | |||
216 | return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, | ||
217 | sizeof(struct iwm_lmac_cal_cfg_cmd), 1); | ||
218 | } | ||
219 | |||
220 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) | ||
221 | { | ||
222 | struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; | ||
223 | |||
224 | memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); | ||
225 | |||
226 | cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); | ||
227 | cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); | ||
228 | |||
229 | return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, | ||
230 | sizeof(struct iwm_lmac_cal_cfg_cmd), 0); | ||
231 | } | ||
232 | |||
233 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) | ||
234 | { | ||
235 | struct iwm_calib_rxiq *rxiq; | ||
236 | u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); | ||
237 | int grplen = sizeof(struct iwm_calib_rxiq_group); | ||
238 | |||
239 | rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); | ||
240 | if (!rxiq) { | ||
241 | IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); | ||
242 | return -ENOMEM; | ||
243 | } | ||
244 | |||
245 | eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); | ||
246 | if (IS_ERR(eeprom_rxiq)) { | ||
247 | IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); | ||
248 | kfree(rxiq); | ||
249 | return PTR_ERR(eeprom_rxiq); | ||
250 | } | ||
251 | |||
252 | iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; | ||
253 | iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); | ||
254 | |||
255 | rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; | ||
256 | rxiq->hdr.first_grp = 0; | ||
257 | rxiq->hdr.grp_num = 1; | ||
258 | rxiq->hdr.all_data_valid = 1; | ||
259 | |||
260 | memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); | ||
261 | memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | int iwm_send_calib_results(struct iwm_priv *iwm) | ||
267 | { | ||
268 | int i, ret = 0; | ||
269 | |||
270 | for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { | ||
271 | if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, | ||
272 | &iwm->calib_done_map)) { | ||
273 | IWM_DBG_CMD(iwm, DBG, | ||
274 | "Send calibration %d result\n", i); | ||
275 | ret |= iwm_send_lmac_ptrough_cmd(iwm, | ||
276 | REPLY_PHY_CALIBRATION_CMD, | ||
277 | iwm->calib_res[i].buf, | ||
278 | iwm->calib_res[i].size, 0); | ||
279 | |||
280 | kfree(iwm->calib_res[i].buf); | ||
281 | iwm->calib_res[i].buf = NULL; | ||
282 | iwm->calib_res[i].size = 0; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit) | ||
290 | { | ||
291 | struct iwm_ct_kill_cfg_cmd cmd; | ||
292 | |||
293 | cmd.entry_threshold = entry; | ||
294 | cmd.exit_threshold = exit; | ||
295 | |||
296 | return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd, | ||
297 | sizeof(struct iwm_ct_kill_cfg_cmd), 0); | ||
298 | } | ||
299 | |||
300 | int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) | ||
301 | { | ||
302 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
303 | struct iwm_umac_cmd umac_cmd; | ||
304 | struct iwm_umac_cmd_reset reset; | ||
305 | |||
306 | reset.flags = reset_flags; | ||
307 | |||
308 | umac_cmd.id = UMAC_CMD_OPCODE_RESET; | ||
309 | umac_cmd.resp = resp; | ||
310 | |||
311 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, | ||
312 | sizeof(struct iwm_umac_cmd_reset)); | ||
313 | } | ||
314 | |||
315 | int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) | ||
316 | { | ||
317 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
318 | struct iwm_umac_cmd umac_cmd; | ||
319 | struct iwm_umac_cmd_set_param_fix param; | ||
320 | |||
321 | if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && | ||
322 | (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) | ||
323 | return -EINVAL; | ||
324 | |||
325 | umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; | ||
326 | umac_cmd.resp = 0; | ||
327 | |||
328 | param.tbl = cpu_to_le16(tbl); | ||
329 | param.key = cpu_to_le16(key); | ||
330 | param.value = cpu_to_le32(value); | ||
331 | |||
332 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ¶m, | ||
333 | sizeof(struct iwm_umac_cmd_set_param_fix)); | ||
334 | } | ||
335 | |||
336 | int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, | ||
337 | void *payload, u16 payload_size) | ||
338 | { | ||
339 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
340 | struct iwm_umac_cmd umac_cmd; | ||
341 | struct iwm_umac_cmd_set_param_var *param_hdr; | ||
342 | u8 *param; | ||
343 | int ret; | ||
344 | |||
345 | param = kzalloc(payload_size + | ||
346 | sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); | ||
347 | if (!param) { | ||
348 | IWM_ERR(iwm, "Couldn't allocate param\n"); | ||
349 | return -ENOMEM; | ||
350 | } | ||
351 | |||
352 | param_hdr = (struct iwm_umac_cmd_set_param_var *)param; | ||
353 | |||
354 | umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; | ||
355 | umac_cmd.resp = 0; | ||
356 | |||
357 | param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); | ||
358 | param_hdr->key = cpu_to_le16(key); | ||
359 | param_hdr->len = cpu_to_le16(payload_size); | ||
360 | memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), | ||
361 | payload, payload_size); | ||
362 | |||
363 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, | ||
364 | sizeof(struct iwm_umac_cmd_set_param_var) + | ||
365 | payload_size); | ||
366 | kfree(param); | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) | ||
372 | { | ||
373 | int ret; | ||
374 | |||
375 | /* Use UMAC default values */ | ||
376 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
377 | CFG_POWER_INDEX, iwm->conf.power_index); | ||
378 | if (ret < 0) | ||
379 | return ret; | ||
380 | |||
381 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, | ||
382 | CFG_FRAG_THRESHOLD, | ||
383 | iwm->conf.frag_threshold); | ||
384 | if (ret < 0) | ||
385 | return ret; | ||
386 | |||
387 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
388 | CFG_RTS_THRESHOLD, | ||
389 | iwm->conf.rts_threshold); | ||
390 | if (ret < 0) | ||
391 | return ret; | ||
392 | |||
393 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
394 | CFG_CTS_TO_SELF, iwm->conf.cts_to_self); | ||
395 | if (ret < 0) | ||
396 | return ret; | ||
397 | |||
398 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
399 | CFG_WIRELESS_MODE, | ||
400 | iwm->conf.wireless_mode); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
405 | CFG_COEX_MODE, modparam_wiwi); | ||
406 | if (ret < 0) | ||
407 | return ret; | ||
408 | |||
409 | /* | ||
410 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
411 | CFG_ASSOCIATION_TIMEOUT, | ||
412 | iwm->conf.assoc_timeout); | ||
413 | if (ret < 0) | ||
414 | return ret; | ||
415 | |||
416 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
417 | CFG_ROAM_TIMEOUT, | ||
418 | iwm->conf.roam_timeout); | ||
419 | if (ret < 0) | ||
420 | return ret; | ||
421 | |||
422 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
423 | CFG_WIRELESS_MODE, | ||
424 | WIRELESS_MODE_11A | WIRELESS_MODE_11G); | ||
425 | if (ret < 0) | ||
426 | return ret; | ||
427 | */ | ||
428 | |||
429 | ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, | ||
430 | iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); | ||
431 | if (ret < 0) | ||
432 | return ret; | ||
433 | |||
434 | /* UMAC PM static configurations */ | ||
435 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
436 | CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); | ||
437 | if (ret < 0) | ||
438 | return ret; | ||
439 | |||
440 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
441 | CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); | ||
442 | if (ret < 0) | ||
443 | return ret; | ||
444 | |||
445 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
446 | CFG_PM_CTRL_FLAGS, 0x1); | ||
447 | if (ret < 0) | ||
448 | return ret; | ||
449 | |||
450 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
451 | CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); | ||
452 | if (ret < 0) | ||
453 | return ret; | ||
454 | |||
455 | /* reset UMAC */ | ||
456 | ret = iwm_send_umac_reset(iwm, reset_flags, 1); | ||
457 | if (ret < 0) | ||
458 | return ret; | ||
459 | |||
460 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, | ||
461 | WAIT_NOTIF_TIMEOUT); | ||
462 | if (ret) { | ||
463 | IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) | ||
471 | { | ||
472 | struct iwm_udma_wifi_cmd udma_cmd; | ||
473 | struct iwm_umac_cmd umac_cmd; | ||
474 | struct iwm_tx_info *tx_info = skb_to_tx_info(skb); | ||
475 | |||
476 | udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ | ||
477 | udma_cmd.credit_group = pool_id; | ||
478 | udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; | ||
479 | udma_cmd.lmac_offset = 0; | ||
480 | |||
481 | umac_cmd.id = REPLY_TX; | ||
482 | umac_cmd.color = tx_info->color; | ||
483 | umac_cmd.resp = 0; | ||
484 | |||
485 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, | ||
486 | skb->data, skb->len); | ||
487 | } | ||
488 | |||
489 | static int iwm_target_read(struct iwm_priv *iwm, __le32 address, | ||
490 | u8 *response, u32 resp_size) | ||
491 | { | ||
492 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
493 | struct iwm_nonwifi_cmd *cmd; | ||
494 | u16 seq_num; | ||
495 | int ret = 0; | ||
496 | |||
497 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; | ||
498 | target_cmd.addr = address; | ||
499 | target_cmd.op1_sz = cpu_to_le32(resp_size); | ||
500 | target_cmd.op2 = 0; | ||
501 | target_cmd.handle_by_hw = 0; | ||
502 | target_cmd.resp = 1; | ||
503 | target_cmd.eop = 1; | ||
504 | |||
505 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
506 | if (ret < 0) { | ||
507 | IWM_ERR(iwm, "Couldn't send READ command\n"); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | /* When succeeding, the send_target routine returns the seq number */ | ||
512 | seq_num = ret; | ||
513 | |||
514 | ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, | ||
515 | (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, | ||
516 | UMAC_HDI_OUT_OPCODE_READ)) != NULL, | ||
517 | 2 * HZ); | ||
518 | |||
519 | if (!ret) { | ||
520 | IWM_ERR(iwm, "Didn't receive a target READ answer\n"); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), | ||
525 | resp_size); | ||
526 | |||
527 | kfree(cmd); | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) | ||
533 | { | ||
534 | int ret; | ||
535 | u8 mac_align[ALIGN(ETH_ALEN, 8)]; | ||
536 | |||
537 | ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), | ||
538 | mac_align, sizeof(mac_align)); | ||
539 | if (ret) | ||
540 | return ret; | ||
541 | |||
542 | if (is_valid_ether_addr(mac_align)) | ||
543 | memcpy(mac, mac_align, ETH_ALEN); | ||
544 | else { | ||
545 | IWM_ERR(iwm, "Invalid EEPROM MAC\n"); | ||
546 | memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); | ||
547 | get_random_bytes(&mac[3], 3); | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int iwm_check_profile(struct iwm_priv *iwm) | ||
554 | { | ||
555 | if (!iwm->umac_profile_active) | ||
556 | return -EAGAIN; | ||
557 | |||
558 | if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && | ||
559 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && | ||
560 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && | ||
561 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { | ||
562 | IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", | ||
563 | iwm->umac_profile->sec.ucast_cipher); | ||
564 | return -EAGAIN; | ||
565 | } | ||
566 | |||
567 | if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && | ||
568 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && | ||
569 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && | ||
570 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { | ||
571 | IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", | ||
572 | iwm->umac_profile->sec.mcast_cipher); | ||
573 | return -EAGAIN; | ||
574 | } | ||
575 | |||
576 | if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || | ||
577 | iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && | ||
578 | (iwm->umac_profile->sec.ucast_cipher != | ||
579 | iwm->umac_profile->sec.mcast_cipher)) { | ||
580 | IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); | ||
581 | } | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) | ||
587 | { | ||
588 | struct iwm_umac_tx_key_id tx_key_id; | ||
589 | int ret; | ||
590 | |||
591 | ret = iwm_check_profile(iwm); | ||
592 | if (ret < 0) | ||
593 | return ret; | ||
594 | |||
595 | /* UMAC only allows to set default key for WEP and auth type is | ||
596 | * NOT 802.1X or RSNA. */ | ||
597 | if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && | ||
598 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || | ||
599 | iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || | ||
600 | iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) | ||
601 | return 0; | ||
602 | |||
603 | tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; | ||
604 | tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - | ||
605 | sizeof(struct iwm_umac_wifi_if)); | ||
606 | |||
607 | tx_key_id.key_idx = key_idx; | ||
608 | |||
609 | return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); | ||
610 | } | ||
611 | |||
612 | int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) | ||
613 | { | ||
614 | int ret = 0; | ||
615 | u8 cmd[64], *sta_addr, *key_data, key_len; | ||
616 | s8 key_idx; | ||
617 | u16 cmd_size = 0; | ||
618 | struct iwm_umac_key_hdr *key_hdr = &key->hdr; | ||
619 | struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; | ||
620 | struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; | ||
621 | struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; | ||
622 | struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; | ||
623 | |||
624 | if (!remove) { | ||
625 | ret = iwm_check_profile(iwm); | ||
626 | if (ret < 0) | ||
627 | return ret; | ||
628 | } | ||
629 | |||
630 | sta_addr = key->hdr.mac; | ||
631 | key_data = key->key; | ||
632 | key_len = key->key_len; | ||
633 | key_idx = key->hdr.key_idx; | ||
634 | |||
635 | if (!remove) { | ||
636 | u8 auth_type = iwm->umac_profile->sec.auth_type; | ||
637 | |||
638 | IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); | ||
639 | IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); | ||
640 | IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", | ||
641 | key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); | ||
642 | |||
643 | IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", | ||
644 | iwm->umac_profile->sec.mcast_cipher, | ||
645 | iwm->umac_profile->sec.ucast_cipher); | ||
646 | IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", | ||
647 | iwm->umac_profile->sec.auth_type, | ||
648 | iwm->umac_profile->sec.flags); | ||
649 | |||
650 | switch (key->cipher) { | ||
651 | case WLAN_CIPHER_SUITE_WEP40: | ||
652 | wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; | ||
653 | wep40->hdr.buf_size = | ||
654 | cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - | ||
655 | sizeof(struct iwm_umac_wifi_if)); | ||
656 | |||
657 | memcpy(&wep40->key_hdr, key_hdr, | ||
658 | sizeof(struct iwm_umac_key_hdr)); | ||
659 | memcpy(wep40->key, key_data, key_len); | ||
660 | wep40->static_key = | ||
661 | !!((auth_type != UMAC_AUTH_TYPE_8021X) && | ||
662 | (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); | ||
663 | |||
664 | cmd_size = sizeof(struct iwm_umac_key_wep40); | ||
665 | break; | ||
666 | |||
667 | case WLAN_CIPHER_SUITE_WEP104: | ||
668 | wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; | ||
669 | wep104->hdr.buf_size = | ||
670 | cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - | ||
671 | sizeof(struct iwm_umac_wifi_if)); | ||
672 | |||
673 | memcpy(&wep104->key_hdr, key_hdr, | ||
674 | sizeof(struct iwm_umac_key_hdr)); | ||
675 | memcpy(wep104->key, key_data, key_len); | ||
676 | wep104->static_key = | ||
677 | !!((auth_type != UMAC_AUTH_TYPE_8021X) && | ||
678 | (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); | ||
679 | |||
680 | cmd_size = sizeof(struct iwm_umac_key_wep104); | ||
681 | break; | ||
682 | |||
683 | case WLAN_CIPHER_SUITE_CCMP: | ||
684 | key_hdr->key_idx++; | ||
685 | ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; | ||
686 | ccmp->hdr.buf_size = | ||
687 | cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - | ||
688 | sizeof(struct iwm_umac_wifi_if)); | ||
689 | |||
690 | memcpy(&ccmp->key_hdr, key_hdr, | ||
691 | sizeof(struct iwm_umac_key_hdr)); | ||
692 | |||
693 | memcpy(ccmp->key, key_data, key_len); | ||
694 | |||
695 | if (key->seq_len) | ||
696 | memcpy(ccmp->iv_count, key->seq, key->seq_len); | ||
697 | |||
698 | cmd_size = sizeof(struct iwm_umac_key_ccmp); | ||
699 | break; | ||
700 | |||
701 | case WLAN_CIPHER_SUITE_TKIP: | ||
702 | key_hdr->key_idx++; | ||
703 | tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; | ||
704 | tkip->hdr.buf_size = | ||
705 | cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - | ||
706 | sizeof(struct iwm_umac_wifi_if)); | ||
707 | |||
708 | memcpy(&tkip->key_hdr, key_hdr, | ||
709 | sizeof(struct iwm_umac_key_hdr)); | ||
710 | |||
711 | memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); | ||
712 | memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, | ||
713 | IWM_TKIP_MIC_SIZE); | ||
714 | memcpy(tkip->mic_rx_key, | ||
715 | key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, | ||
716 | IWM_TKIP_MIC_SIZE); | ||
717 | |||
718 | if (key->seq_len) | ||
719 | memcpy(ccmp->iv_count, key->seq, key->seq_len); | ||
720 | |||
721 | cmd_size = sizeof(struct iwm_umac_key_tkip); | ||
722 | break; | ||
723 | |||
724 | default: | ||
725 | return -ENOTSUPP; | ||
726 | } | ||
727 | |||
728 | if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || | ||
729 | (key->cipher == WLAN_CIPHER_SUITE_CCMP)) | ||
730 | /* | ||
731 | * UGLY_UGLY_UGLY | ||
732 | * Copied HACK from the MWG driver. | ||
733 | * Without it, the key is set before the second | ||
734 | * EAPOL frame is sent, and the latter is thus | ||
735 | * encrypted. | ||
736 | */ | ||
737 | schedule_timeout_interruptible(usecs_to_jiffies(300)); | ||
738 | |||
739 | ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); | ||
740 | } else { | ||
741 | struct iwm_umac_key_remove key_remove; | ||
742 | |||
743 | IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); | ||
744 | |||
745 | key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; | ||
746 | key_remove.hdr.buf_size = | ||
747 | cpu_to_le16(sizeof(struct iwm_umac_key_remove) - | ||
748 | sizeof(struct iwm_umac_wifi_if)); | ||
749 | memcpy(&key_remove.key_hdr, key_hdr, | ||
750 | sizeof(struct iwm_umac_key_hdr)); | ||
751 | |||
752 | ret = iwm_send_wifi_if_cmd(iwm, &key_remove, | ||
753 | sizeof(struct iwm_umac_key_remove), | ||
754 | 1); | ||
755 | if (ret) | ||
756 | return ret; | ||
757 | |||
758 | iwm->keys[key_idx].key_len = 0; | ||
759 | } | ||
760 | |||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | |||
765 | int iwm_send_mlme_profile(struct iwm_priv *iwm) | ||
766 | { | ||
767 | int ret; | ||
768 | struct iwm_umac_profile profile; | ||
769 | |||
770 | memcpy(&profile, iwm->umac_profile, sizeof(profile)); | ||
771 | |||
772 | profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; | ||
773 | profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - | ||
774 | sizeof(struct iwm_umac_wifi_if)); | ||
775 | |||
776 | ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); | ||
777 | if (ret) { | ||
778 | IWM_ERR(iwm, "Send profile command failed\n"); | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm) | ||
787 | { | ||
788 | struct iwm_umac_invalidate_profile invalid; | ||
789 | |||
790 | invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; | ||
791 | invalid.hdr.buf_size = | ||
792 | cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - | ||
793 | sizeof(struct iwm_umac_wifi_if)); | ||
794 | |||
795 | invalid.reason = WLAN_REASON_UNSPECIFIED; | ||
796 | |||
797 | return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); | ||
798 | } | ||
799 | |||
800 | int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) | ||
801 | { | ||
802 | int ret; | ||
803 | |||
804 | ret = __iwm_invalidate_mlme_profile(iwm); | ||
805 | if (ret) | ||
806 | return ret; | ||
807 | |||
808 | ret = wait_event_interruptible_timeout(iwm->mlme_queue, | ||
809 | (iwm->umac_profile_active == 0), 5 * HZ); | ||
810 | |||
811 | return ret ? 0 : -EBUSY; | ||
812 | } | ||
813 | |||
814 | int iwm_tx_power_trigger(struct iwm_priv *iwm) | ||
815 | { | ||
816 | struct iwm_umac_pwr_trigger pwr_trigger; | ||
817 | |||
818 | pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER; | ||
819 | pwr_trigger.hdr.buf_size = | ||
820 | cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) - | ||
821 | sizeof(struct iwm_umac_wifi_if)); | ||
822 | |||
823 | |||
824 | return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1); | ||
825 | } | ||
826 | |||
827 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) | ||
828 | { | ||
829 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
830 | struct iwm_umac_cmd umac_cmd; | ||
831 | struct iwm_umac_cmd_stats_req stats_req; | ||
832 | |||
833 | stats_req.flags = cpu_to_le32(flags); | ||
834 | |||
835 | umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; | ||
836 | umac_cmd.resp = 0; | ||
837 | |||
838 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, | ||
839 | sizeof(struct iwm_umac_cmd_stats_req)); | ||
840 | } | ||
841 | |||
842 | int iwm_send_umac_channel_list(struct iwm_priv *iwm) | ||
843 | { | ||
844 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
845 | struct iwm_umac_cmd umac_cmd; | ||
846 | struct iwm_umac_cmd_get_channel_list *ch_list; | ||
847 | int size = sizeof(struct iwm_umac_cmd_get_channel_list) + | ||
848 | sizeof(struct iwm_umac_channel_info) * 4; | ||
849 | int ret; | ||
850 | |||
851 | ch_list = kzalloc(size, GFP_KERNEL); | ||
852 | if (!ch_list) { | ||
853 | IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); | ||
854 | return -ENOMEM; | ||
855 | } | ||
856 | |||
857 | ch_list->ch[0].band = UMAC_BAND_2GHZ; | ||
858 | ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
859 | ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; | ||
860 | |||
861 | ch_list->ch[1].band = UMAC_BAND_5GHZ; | ||
862 | ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
863 | ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; | ||
864 | |||
865 | ch_list->ch[2].band = UMAC_BAND_2GHZ; | ||
866 | ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
867 | ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; | ||
868 | |||
869 | ch_list->ch[3].band = UMAC_BAND_5GHZ; | ||
870 | ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
871 | ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; | ||
872 | |||
873 | ch_list->count = cpu_to_le16(4); | ||
874 | |||
875 | umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; | ||
876 | umac_cmd.resp = 1; | ||
877 | |||
878 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); | ||
879 | |||
880 | kfree(ch_list); | ||
881 | |||
882 | return ret; | ||
883 | } | ||
884 | |||
885 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, | ||
886 | int ssid_num) | ||
887 | { | ||
888 | struct iwm_umac_cmd_scan_request req; | ||
889 | int i, ret; | ||
890 | |||
891 | memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); | ||
892 | |||
893 | req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; | ||
894 | req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) | ||
895 | - sizeof(struct iwm_umac_wifi_if)); | ||
896 | req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; | ||
897 | req.timeout = 2; | ||
898 | req.seq_num = iwm->scan_id; | ||
899 | req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); | ||
900 | |||
901 | for (i = 0; i < req.ssid_num; i++) { | ||
902 | memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); | ||
903 | req.ssids[i].ssid_len = ssids[i].ssid_len; | ||
904 | } | ||
905 | |||
906 | ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); | ||
907 | if (ret) { | ||
908 | IWM_ERR(iwm, "Couldn't send scan request\n"); | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | iwm->scan_id = (iwm->scan_id + 1) % IWM_SCAN_ID_MAX; | ||
913 | |||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) | ||
918 | { | ||
919 | struct cfg80211_ssid one_ssid; | ||
920 | |||
921 | if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) | ||
922 | return 0; | ||
923 | |||
924 | one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); | ||
925 | memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); | ||
926 | |||
927 | return iwm_scan_ssids(iwm, &one_ssid, 1); | ||
928 | } | ||
929 | |||
930 | int iwm_target_reset(struct iwm_priv *iwm) | ||
931 | { | ||
932 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
933 | |||
934 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; | ||
935 | target_cmd.addr = 0; | ||
936 | target_cmd.op1_sz = 0; | ||
937 | target_cmd.op2 = 0; | ||
938 | target_cmd.handle_by_hw = 0; | ||
939 | target_cmd.resp = 0; | ||
940 | target_cmd.eop = 1; | ||
941 | |||
942 | return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
943 | } | ||
944 | |||
945 | int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, | ||
946 | struct iwm_umac_notif_stop_resume_tx *ntf) | ||
947 | { | ||
948 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
949 | struct iwm_umac_cmd umac_cmd; | ||
950 | struct iwm_umac_cmd_stop_resume_tx stp_res_cmd; | ||
951 | struct iwm_sta_info *sta_info; | ||
952 | u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id); | ||
953 | int i; | ||
954 | |||
955 | sta_info = &iwm->sta_table[sta_id]; | ||
956 | if (!sta_info->valid) { | ||
957 | IWM_ERR(iwm, "Invalid STA: %d\n", sta_id); | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | |||
961 | umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX; | ||
962 | umac_cmd.resp = 0; | ||
963 | |||
964 | stp_res_cmd.flags = ntf->flags; | ||
965 | stp_res_cmd.sta_id = ntf->sta_id; | ||
966 | stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk; | ||
967 | for (i = 0; i < IWM_UMAC_TID_NR; i++) | ||
968 | stp_res_cmd.last_seq_num[i] = | ||
969 | sta_info->tid_info[i].last_seq_num; | ||
970 | |||
971 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd, | ||
972 | sizeof(struct iwm_umac_cmd_stop_resume_tx)); | ||
973 | |||
974 | } | ||
975 | |||
976 | int iwm_send_pmkid_update(struct iwm_priv *iwm, | ||
977 | struct cfg80211_pmksa *pmksa, u32 command) | ||
978 | { | ||
979 | struct iwm_umac_pmkid_update update; | ||
980 | int ret; | ||
981 | |||
982 | memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); | ||
983 | |||
984 | update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE; | ||
985 | update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) - | ||
986 | sizeof(struct iwm_umac_wifi_if)); | ||
987 | |||
988 | update.command = cpu_to_le32(command); | ||
989 | if (pmksa->bssid) | ||
990 | memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); | ||
991 | if (pmksa->pmkid) | ||
992 | memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); | ||
993 | |||
994 | ret = iwm_send_wifi_if_cmd(iwm, &update, | ||
995 | sizeof(struct iwm_umac_pmkid_update), 0); | ||
996 | if (ret) { | ||
997 | IWM_ERR(iwm, "PMKID update command failed\n"); | ||
998 | return ret; | ||
999 | } | ||
1000 | |||
1001 | return 0; | ||
1002 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h deleted file mode 100644 index 6421689f5e8e..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ /dev/null | |||
@@ -1,509 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_COMMANDS_H__ | ||
40 | #define __IWM_COMMANDS_H__ | ||
41 | |||
42 | #include <linux/ieee80211.h> | ||
43 | |||
44 | #define IWM_BARKER_REBOOT_NOTIFICATION 0xF | ||
45 | #define IWM_ACK_BARKER_NOTIFICATION 0x10 | ||
46 | |||
47 | /* UMAC commands */ | ||
48 | #define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001 | ||
49 | #define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002 | ||
50 | #define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004 | ||
51 | #define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008 | ||
52 | #define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010 | ||
53 | #define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040 | ||
54 | #define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080 | ||
55 | #define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100 | ||
56 | |||
57 | struct iwm_umac_cmd_reset { | ||
58 | __le32 flags; | ||
59 | } __packed; | ||
60 | |||
61 | #define UMAC_PARAM_TBL_ORD_FIX 0x0 | ||
62 | #define UMAC_PARAM_TBL_ORD_VAR 0x1 | ||
63 | #define UMAC_PARAM_TBL_CFG_FIX 0x2 | ||
64 | #define UMAC_PARAM_TBL_CFG_VAR 0x3 | ||
65 | #define UMAC_PARAM_TBL_BSS_TRK 0x4 | ||
66 | #define UMAC_PARAM_TBL_FA_CFG_FIX 0x5 | ||
67 | #define UMAC_PARAM_TBL_STA 0x6 | ||
68 | #define UMAC_PARAM_TBL_CHN 0x7 | ||
69 | #define UMAC_PARAM_TBL_STATISTICS 0x8 | ||
70 | |||
71 | /* fast access table */ | ||
72 | enum { | ||
73 | CFG_FRAG_THRESHOLD = 0, | ||
74 | CFG_FRAME_RETRY_LIMIT, | ||
75 | CFG_OS_QUEUE_UTIL_TH, | ||
76 | CFG_RX_FILTER, | ||
77 | /* <-- LAST --> */ | ||
78 | FAST_ACCESS_CFG_TBL_FIX_LAST | ||
79 | }; | ||
80 | |||
81 | /* fixed size table */ | ||
82 | enum { | ||
83 | CFG_POWER_INDEX = 0, | ||
84 | CFG_PM_LEGACY_RX_TIMEOUT, | ||
85 | CFG_PM_LEGACY_TX_TIMEOUT, | ||
86 | CFG_PM_CTRL_FLAGS, | ||
87 | CFG_PM_KEEP_ALIVE_IN_BEACONS, | ||
88 | CFG_BT_ON_THRESHOLD, | ||
89 | CFG_RTS_THRESHOLD, | ||
90 | CFG_CTS_TO_SELF, | ||
91 | CFG_COEX_MODE, | ||
92 | CFG_WIRELESS_MODE, | ||
93 | CFG_ASSOCIATION_TIMEOUT, | ||
94 | CFG_ROAM_TIMEOUT, | ||
95 | CFG_CAPABILITY_SUPPORTED_RATES, | ||
96 | CFG_SCAN_ALLOWED_UNASSOC_FLAGS, | ||
97 | CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS, | ||
98 | CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS, | ||
99 | CFG_SCAN_INTERNAL_PERIODIC_ENABLED, | ||
100 | CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT, | ||
101 | CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC, | ||
102 | CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, | ||
103 | CFG_TLC_SUPPORTED_TX_HT_RATES, | ||
104 | CFG_TLC_SUPPORTED_TX_RATES, | ||
105 | CFG_TLC_SPATIAL_STREAM_SUPPORTED, | ||
106 | CFG_TLC_RETRY_PER_RATE, | ||
107 | CFG_TLC_RETRY_PER_HT_RATE, | ||
108 | CFG_TLC_FIXED_MCS, | ||
109 | CFG_TLC_CONTROL_FLAGS, | ||
110 | CFG_TLC_SR_MIN_FAIL, | ||
111 | CFG_TLC_SR_MIN_PASS, | ||
112 | CFG_TLC_HT_STAY_IN_COL_PASS_THRESH, | ||
113 | CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH, | ||
114 | CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH, | ||
115 | CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH, | ||
116 | CFG_TLC_HT_FLUSH_STATS_PACKETS, | ||
117 | CFG_TLC_LEGACY_FLUSH_STATS_PACKETS, | ||
118 | CFG_TLC_LEGACY_FLUSH_STATS_MS, | ||
119 | CFG_TLC_HT_FLUSH_STATS_MS, | ||
120 | CFG_TLC_STAY_IN_COL_TIME_OUT, | ||
121 | CFG_TLC_AGG_SHORT_LIM, | ||
122 | CFG_TLC_AGG_LONG_LIM, | ||
123 | CFG_TLC_HT_SR_NO_DECREASE, | ||
124 | CFG_TLC_LEGACY_SR_NO_DECREASE, | ||
125 | CFG_TLC_SR_FORCE_DECREASE, | ||
126 | CFG_TLC_SR_ALLOW_INCREASE, | ||
127 | CFG_TLC_AGG_SET_LONG, | ||
128 | CFG_TLC_AUTO_AGGREGATION, | ||
129 | CFG_TLC_AGG_THRESHOLD, | ||
130 | CFG_TLC_TID_LOAD_THRESHOLD, | ||
131 | CFG_TLC_BLOCK_ACK_TIMEOUT, | ||
132 | CFG_TLC_NO_BA_COUNTED_AS_ONE, | ||
133 | CFG_TLC_NUM_BA_STREAMS_ALLOWED, | ||
134 | CFG_TLC_NUM_BA_STREAMS_PRESENT, | ||
135 | CFG_TLC_RENEW_ADDBA_DELAY, | ||
136 | CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, | ||
137 | CFG_TLC_IS_STABLE_IN_HT, | ||
138 | CFG_TLC_SR_SIC_1ST_FAIL, | ||
139 | CFG_TLC_SR_SIC_1ST_PASS, | ||
140 | CFG_TLC_SR_SIC_TOTAL_FAIL, | ||
141 | CFG_TLC_SR_SIC_TOTAL_PASS, | ||
142 | CFG_RLC_CHAIN_CTRL, | ||
143 | CFG_TRK_TABLE_OP_MODE, | ||
144 | CFG_TRK_TABLE_RSSI_THRESHOLD, | ||
145 | CFG_TX_PWR_TARGET, /* Used By xVT */ | ||
146 | CFG_TX_PWR_LIMIT_USR, | ||
147 | CFG_TX_PWR_LIMIT_BSS, /* 11d limit */ | ||
148 | CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */ | ||
149 | CFG_TX_PWR_MODE, | ||
150 | CFG_MLME_DBG_NOTIF_BLOCK, | ||
151 | CFG_BT_OFF_BECONS_INTERVALS, | ||
152 | CFG_BT_FRAG_DURATION, | ||
153 | CFG_ACTIVE_CHAINS, | ||
154 | CFG_CALIB_CTRL, | ||
155 | CFG_CAPABILITY_SUPPORTED_HT_RATES, | ||
156 | CFG_HT_MAC_PARAM_INFO, | ||
157 | CFG_MIMO_PS_MODE, | ||
158 | CFG_HT_DEFAULT_CAPABILIES_INFO, | ||
159 | CFG_LED_SC_RESOLUTION_FACTOR, | ||
160 | CFG_PTAM_ENERGY_CCK_DET_DEFAULT, | ||
161 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT, | ||
162 | CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT, | ||
163 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT, | ||
164 | CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT, | ||
165 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT, | ||
166 | CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT, | ||
167 | CFG_PTAM_ENERGY_CCK_DET_MIN_VAL, | ||
168 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL, | ||
169 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL, | ||
170 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL, | ||
171 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL, | ||
172 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL, | ||
173 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL, | ||
174 | CFG_PTAM_ENERGY_CCK_DET_MAX_VAL, | ||
175 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL, | ||
176 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL, | ||
177 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL, | ||
178 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL, | ||
179 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL, | ||
180 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL, | ||
181 | CFG_PTAM_ENERGY_CCK_DET_STEP_VAL, | ||
182 | CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL, | ||
183 | CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL, | ||
184 | CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL, | ||
185 | CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL, | ||
186 | CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL, | ||
187 | CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL, | ||
188 | CFG_PTAM_LINK_SENS_FA_OFDM_MAX, | ||
189 | CFG_PTAM_LINK_SENS_FA_OFDM_MIN, | ||
190 | CFG_PTAM_LINK_SENS_FA_CCK_MAX, | ||
191 | CFG_PTAM_LINK_SENS_FA_CCK_MIN, | ||
192 | CFG_PTAM_LINK_SENS_NRG_DIFF, | ||
193 | CFG_PTAM_LINK_SENS_NRG_MARGIN, | ||
194 | CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA, | ||
195 | CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK, | ||
196 | CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD, | ||
197 | CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD, | ||
198 | CFG_AGG_MGG_ADDBA_BUF_SIZE, | ||
199 | CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT, | ||
200 | CFG_AGG_MGG_ADDBA_DEBUG_FLAGS, | ||
201 | CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD, | ||
202 | CFG_SCAN_PERIODIC_COEF_RSSI_HIGH, | ||
203 | CFG_11D_ENABLED, | ||
204 | CFG_11H_FEATURE_FLAGS, | ||
205 | |||
206 | /* <-- LAST --> */ | ||
207 | CFG_TBL_FIX_LAST | ||
208 | }; | ||
209 | |||
210 | /* variable size table */ | ||
211 | enum { | ||
212 | CFG_NET_ADDR = 0, | ||
213 | CFG_LED_PATTERN_TABLE, | ||
214 | |||
215 | /* <-- LAST --> */ | ||
216 | CFG_TBL_VAR_LAST | ||
217 | }; | ||
218 | |||
219 | struct iwm_umac_cmd_set_param_fix { | ||
220 | __le16 tbl; | ||
221 | __le16 key; | ||
222 | __le32 value; | ||
223 | } __packed; | ||
224 | |||
225 | struct iwm_umac_cmd_set_param_var { | ||
226 | __le16 tbl; | ||
227 | __le16 key; | ||
228 | __le16 len; | ||
229 | __le16 reserved; | ||
230 | } __packed; | ||
231 | |||
232 | struct iwm_umac_cmd_get_param { | ||
233 | __le16 tbl; | ||
234 | __le16 key; | ||
235 | } __packed; | ||
236 | |||
237 | struct iwm_umac_cmd_get_param_resp { | ||
238 | __le16 tbl; | ||
239 | __le16 key; | ||
240 | __le16 len; | ||
241 | __le16 reserved; | ||
242 | } __packed; | ||
243 | |||
244 | struct iwm_umac_cmd_eeprom_proxy_hdr { | ||
245 | __le32 type; | ||
246 | __le32 offset; | ||
247 | __le32 len; | ||
248 | } __packed; | ||
249 | |||
250 | struct iwm_umac_cmd_eeprom_proxy { | ||
251 | struct iwm_umac_cmd_eeprom_proxy_hdr hdr; | ||
252 | u8 buf[0]; | ||
253 | } __packed; | ||
254 | |||
255 | #define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1 | ||
256 | #define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2 | ||
257 | |||
258 | #define UMAC_CHANNEL_FLAG_VALID BIT(0) | ||
259 | #define UMAC_CHANNEL_FLAG_IBSS BIT(1) | ||
260 | #define UMAC_CHANNEL_FLAG_ACTIVE BIT(3) | ||
261 | #define UMAC_CHANNEL_FLAG_RADAR BIT(4) | ||
262 | #define UMAC_CHANNEL_FLAG_DFS BIT(7) | ||
263 | |||
264 | struct iwm_umac_channel_info { | ||
265 | u8 band; | ||
266 | u8 type; | ||
267 | u8 reserved; | ||
268 | u8 flags; | ||
269 | __le32 channels_mask; | ||
270 | } __packed; | ||
271 | |||
272 | struct iwm_umac_cmd_get_channel_list { | ||
273 | __le16 count; | ||
274 | __le16 reserved; | ||
275 | struct iwm_umac_channel_info ch[0]; | ||
276 | } __packed; | ||
277 | |||
278 | |||
279 | /* UMAC WiFi interface commands */ | ||
280 | |||
281 | /* Coexistence mode */ | ||
282 | #define COEX_MODE_SA 0x1 | ||
283 | #define COEX_MODE_XOR 0x2 | ||
284 | #define COEX_MODE_CM 0x3 | ||
285 | #define COEX_MODE_MAX 0x4 | ||
286 | |||
287 | /* Wireless mode */ | ||
288 | #define WIRELESS_MODE_11A 0x1 | ||
289 | #define WIRELESS_MODE_11G 0x2 | ||
290 | #define WIRELESS_MODE_11N 0x4 | ||
291 | |||
292 | #define UMAC_PROFILE_EX_IE_REQUIRED 0x1 | ||
293 | #define UMAC_PROFILE_QOS_ALLOWED 0x2 | ||
294 | |||
295 | /* Scanning */ | ||
296 | #define UMAC_WIFI_IF_PROBE_OPTION_MAX 10 | ||
297 | |||
298 | #define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0 | ||
299 | #define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1 | ||
300 | #define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2 | ||
301 | #define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3 | ||
302 | |||
303 | struct iwm_umac_ssid { | ||
304 | u8 ssid_len; | ||
305 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
306 | u8 reserved[3]; | ||
307 | } __packed; | ||
308 | |||
309 | struct iwm_umac_cmd_scan_request { | ||
310 | struct iwm_umac_wifi_if hdr; | ||
311 | __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */ | ||
312 | u8 ssid_num; | ||
313 | u8 seq_num; | ||
314 | u8 timeout; /* In seconds */ | ||
315 | u8 reserved; | ||
316 | struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX]; | ||
317 | } __packed; | ||
318 | |||
319 | #define UMAC_CIPHER_TYPE_NONE 0xFF | ||
320 | #define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00 | ||
321 | #define UMAC_CIPHER_TYPE_WEP_40 0x01 | ||
322 | #define UMAC_CIPHER_TYPE_WEP_104 0x02 | ||
323 | #define UMAC_CIPHER_TYPE_TKIP 0x04 | ||
324 | #define UMAC_CIPHER_TYPE_CCMP 0x08 | ||
325 | |||
326 | /* Supported authentication types - bitmap */ | ||
327 | #define UMAC_AUTH_TYPE_OPEN 0x00 | ||
328 | #define UMAC_AUTH_TYPE_LEGACY_PSK 0x01 | ||
329 | #define UMAC_AUTH_TYPE_8021X 0x02 | ||
330 | #define UMAC_AUTH_TYPE_RSNA_PSK 0x04 | ||
331 | |||
332 | /* iwm_umac_security.flag is WPA supported -- bits[0:0] */ | ||
333 | #define UMAC_SEC_FLG_WPA_ON_POS 0 | ||
334 | #define UMAC_SEC_FLG_WPA_ON_SEED 1 | ||
335 | #define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \ | ||
336 | UMAC_SEC_FLG_WPA_ON_POS) | ||
337 | |||
338 | /* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */ | ||
339 | #define UMAC_SEC_FLG_RSNA_ON_POS 1 | ||
340 | #define UMAC_SEC_FLG_RSNA_ON_SEED 1 | ||
341 | #define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \ | ||
342 | UMAC_SEC_FLG_RSNA_ON_POS) | ||
343 | |||
344 | /* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ | ||
345 | #define UMAC_SEC_FLG_WSC_ON_POS 2 | ||
346 | #define UMAC_SEC_FLG_WSC_ON_SEED 1 | ||
347 | #define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \ | ||
348 | UMAC_SEC_FLG_WSC_ON_POS) | ||
349 | |||
350 | |||
351 | /* Legacy profile can use only WEP40 and WEP104 for encryption and | ||
352 | * OPEN or PSK for authentication */ | ||
353 | #define UMAC_SEC_FLG_LEGACY_PROFILE 0 | ||
354 | |||
355 | struct iwm_umac_security { | ||
356 | u8 auth_type; | ||
357 | u8 ucast_cipher; | ||
358 | u8 mcast_cipher; | ||
359 | u8 flags; | ||
360 | } __packed; | ||
361 | |||
362 | struct iwm_umac_ibss { | ||
363 | u8 beacon_interval; /* in millisecond */ | ||
364 | u8 atim; /* in millisecond */ | ||
365 | s8 join_only; | ||
366 | u8 band; | ||
367 | u8 channel; | ||
368 | u8 reserved[3]; | ||
369 | } __packed; | ||
370 | |||
371 | #define UMAC_MODE_BSS 0 | ||
372 | #define UMAC_MODE_IBSS 1 | ||
373 | |||
374 | #define UMAC_BSSID_MAX 4 | ||
375 | |||
376 | struct iwm_umac_profile { | ||
377 | struct iwm_umac_wifi_if hdr; | ||
378 | __le32 mode; | ||
379 | struct iwm_umac_ssid ssid; | ||
380 | u8 bssid[UMAC_BSSID_MAX][ETH_ALEN]; | ||
381 | struct iwm_umac_security sec; | ||
382 | struct iwm_umac_ibss ibss; | ||
383 | __le32 channel_2ghz; | ||
384 | __le32 channel_5ghz; | ||
385 | __le16 flags; | ||
386 | u8 wireless_mode; | ||
387 | u8 bss_num; | ||
388 | } __packed; | ||
389 | |||
390 | struct iwm_umac_invalidate_profile { | ||
391 | struct iwm_umac_wifi_if hdr; | ||
392 | u8 reason; | ||
393 | u8 reserved[3]; | ||
394 | } __packed; | ||
395 | |||
396 | /* Encryption key commands */ | ||
397 | struct iwm_umac_key_wep40 { | ||
398 | struct iwm_umac_wifi_if hdr; | ||
399 | struct iwm_umac_key_hdr key_hdr; | ||
400 | u8 key[WLAN_KEY_LEN_WEP40]; | ||
401 | u8 static_key; | ||
402 | u8 reserved[2]; | ||
403 | } __packed; | ||
404 | |||
405 | struct iwm_umac_key_wep104 { | ||
406 | struct iwm_umac_wifi_if hdr; | ||
407 | struct iwm_umac_key_hdr key_hdr; | ||
408 | u8 key[WLAN_KEY_LEN_WEP104]; | ||
409 | u8 static_key; | ||
410 | u8 reserved[2]; | ||
411 | } __packed; | ||
412 | |||
413 | #define IWM_TKIP_KEY_SIZE 16 | ||
414 | #define IWM_TKIP_MIC_SIZE 8 | ||
415 | struct iwm_umac_key_tkip { | ||
416 | struct iwm_umac_wifi_if hdr; | ||
417 | struct iwm_umac_key_hdr key_hdr; | ||
418 | u8 iv_count[6]; | ||
419 | u8 reserved[2]; | ||
420 | u8 tkip_key[IWM_TKIP_KEY_SIZE]; | ||
421 | u8 mic_rx_key[IWM_TKIP_MIC_SIZE]; | ||
422 | u8 mic_tx_key[IWM_TKIP_MIC_SIZE]; | ||
423 | } __packed; | ||
424 | |||
425 | struct iwm_umac_key_ccmp { | ||
426 | struct iwm_umac_wifi_if hdr; | ||
427 | struct iwm_umac_key_hdr key_hdr; | ||
428 | u8 iv_count[6]; | ||
429 | u8 reserved[2]; | ||
430 | u8 key[WLAN_KEY_LEN_CCMP]; | ||
431 | } __packed; | ||
432 | |||
433 | struct iwm_umac_key_remove { | ||
434 | struct iwm_umac_wifi_if hdr; | ||
435 | struct iwm_umac_key_hdr key_hdr; | ||
436 | } __packed; | ||
437 | |||
438 | struct iwm_umac_tx_key_id { | ||
439 | struct iwm_umac_wifi_if hdr; | ||
440 | u8 key_idx; | ||
441 | u8 reserved[3]; | ||
442 | } __packed; | ||
443 | |||
444 | struct iwm_umac_pwr_trigger { | ||
445 | struct iwm_umac_wifi_if hdr; | ||
446 | __le32 reseved; | ||
447 | } __packed; | ||
448 | |||
449 | struct iwm_umac_cmd_stats_req { | ||
450 | __le32 flags; | ||
451 | } __packed; | ||
452 | |||
453 | struct iwm_umac_cmd_stop_resume_tx { | ||
454 | u8 flags; | ||
455 | u8 sta_id; | ||
456 | __le16 stop_resume_tid_msk; | ||
457 | __le16 last_seq_num[IWM_UMAC_TID_NR]; | ||
458 | u16 reserved; | ||
459 | } __packed; | ||
460 | |||
461 | #define IWM_CMD_PMKID_ADD 1 | ||
462 | #define IWM_CMD_PMKID_DEL 2 | ||
463 | #define IWM_CMD_PMKID_FLUSH 3 | ||
464 | |||
465 | struct iwm_umac_pmkid_update { | ||
466 | struct iwm_umac_wifi_if hdr; | ||
467 | __le32 command; | ||
468 | u8 bssid[ETH_ALEN]; | ||
469 | __le16 reserved; | ||
470 | u8 pmkid[WLAN_PMKID_LEN]; | ||
471 | } __packed; | ||
472 | |||
473 | /* LMAC commands */ | ||
474 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); | ||
475 | int iwm_send_prio_table(struct iwm_priv *iwm); | ||
476 | int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); | ||
477 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); | ||
478 | int iwm_send_calib_results(struct iwm_priv *iwm); | ||
479 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); | ||
480 | int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit); | ||
481 | |||
482 | /* UMAC commands */ | ||
483 | int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, | ||
484 | bool resp); | ||
485 | int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp); | ||
486 | int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value); | ||
487 | int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, | ||
488 | void *payload, u16 payload_size); | ||
489 | int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags); | ||
490 | int iwm_send_mlme_profile(struct iwm_priv *iwm); | ||
491 | int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm); | ||
492 | int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); | ||
493 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); | ||
494 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); | ||
495 | int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); | ||
496 | int iwm_tx_power_trigger(struct iwm_priv *iwm); | ||
497 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); | ||
498 | int iwm_send_umac_channel_list(struct iwm_priv *iwm); | ||
499 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, | ||
500 | int ssid_num); | ||
501 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); | ||
502 | int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, | ||
503 | struct iwm_umac_notif_stop_resume_tx *ntf); | ||
504 | int iwm_send_pmkid_update(struct iwm_priv *iwm, | ||
505 | struct cfg80211_pmksa *pmksa, u32 command); | ||
506 | |||
507 | /* UDMA commands */ | ||
508 | int iwm_target_reset(struct iwm_priv *iwm); | ||
509 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h deleted file mode 100644 index a0c13a49ab3c..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/debug.h +++ /dev/null | |||
@@ -1,123 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_DEBUG_H__ | ||
25 | #define __IWM_DEBUG_H__ | ||
26 | |||
27 | #define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a) | ||
28 | #define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a) | ||
29 | #define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a) | ||
30 | #define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a) | ||
31 | |||
32 | #ifdef CONFIG_IWM_DEBUG | ||
33 | |||
34 | #define IWM_DEBUG_MODULE(i, level, module, f, a...) \ | ||
35 | do { \ | ||
36 | if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ | ||
37 | dev_printk(KERN_INFO, (iwm_to_dev(i)), \ | ||
38 | "%s " f, __func__ , ## a); \ | ||
39 | } while (0) | ||
40 | |||
41 | #define IWM_HEXDUMP(i, level, module, pref, buf, len) \ | ||
42 | do { \ | ||
43 | if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ | ||
44 | print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \ | ||
45 | 16, 1, buf, len, 1); \ | ||
46 | } while (0) | ||
47 | |||
48 | #else | ||
49 | |||
50 | #define IWM_DEBUG_MODULE(i, level, module, f, a...) | ||
51 | #define IWM_HEXDUMP(i, level, module, pref, buf, len) | ||
52 | |||
53 | #endif /* CONFIG_IWM_DEBUG */ | ||
54 | |||
55 | /* Debug modules */ | ||
56 | enum iwm_debug_module_id { | ||
57 | IWM_DM_BOOT = 0, | ||
58 | IWM_DM_FW, | ||
59 | IWM_DM_SDIO, | ||
60 | IWM_DM_NTF, | ||
61 | IWM_DM_RX, | ||
62 | IWM_DM_TX, | ||
63 | IWM_DM_MLME, | ||
64 | IWM_DM_CMD, | ||
65 | IWM_DM_WEXT, | ||
66 | __IWM_DM_NR, | ||
67 | }; | ||
68 | #define IWM_DM_DEFAULT 0 | ||
69 | |||
70 | #define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a) | ||
71 | #define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a) | ||
72 | #define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a) | ||
73 | #define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a) | ||
74 | #define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a) | ||
75 | #define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a) | ||
76 | #define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a) | ||
77 | #define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a) | ||
78 | #define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a) | ||
79 | |||
80 | /* Debug levels */ | ||
81 | enum iwm_debug_level { | ||
82 | IWM_DL_NONE = 0, | ||
83 | IWM_DL_ERR, | ||
84 | IWM_DL_WARN, | ||
85 | IWM_DL_INFO, | ||
86 | IWM_DL_DBG, | ||
87 | }; | ||
88 | #define IWM_DL_DEFAULT IWM_DL_ERR | ||
89 | |||
90 | struct iwm_debugfs { | ||
91 | struct iwm_priv *iwm; | ||
92 | struct dentry *rootdir; | ||
93 | struct dentry *devdir; | ||
94 | struct dentry *dbgdir; | ||
95 | struct dentry *txdir; | ||
96 | struct dentry *rxdir; | ||
97 | struct dentry *busdir; | ||
98 | |||
99 | u32 dbg_level; | ||
100 | struct dentry *dbg_level_dentry; | ||
101 | |||
102 | unsigned long dbg_modules; | ||
103 | struct dentry *dbg_modules_dentry; | ||
104 | |||
105 | u8 dbg_module[__IWM_DM_NR]; | ||
106 | struct dentry *dbg_module_dentries[__IWM_DM_NR]; | ||
107 | |||
108 | struct dentry *txq_dentry; | ||
109 | struct dentry *tx_credit_dentry; | ||
110 | struct dentry *rx_ticket_dentry; | ||
111 | |||
112 | struct dentry *fw_err_dentry; | ||
113 | }; | ||
114 | |||
115 | #ifdef CONFIG_IWM_DEBUG | ||
116 | void iwm_debugfs_init(struct iwm_priv *iwm); | ||
117 | void iwm_debugfs_exit(struct iwm_priv *iwm); | ||
118 | #else | ||
119 | static inline void iwm_debugfs_init(struct iwm_priv *iwm) {} | ||
120 | static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {} | ||
121 | #endif | ||
122 | |||
123 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c deleted file mode 100644 index b6199d124bb9..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ /dev/null | |||
@@ -1,488 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/bitops.h> | ||
27 | #include <linux/debugfs.h> | ||
28 | #include <linux/export.h> | ||
29 | |||
30 | #include "iwm.h" | ||
31 | #include "bus.h" | ||
32 | #include "rx.h" | ||
33 | #include "debug.h" | ||
34 | |||
35 | static struct { | ||
36 | u8 id; | ||
37 | char *name; | ||
38 | } iwm_debug_module[__IWM_DM_NR] = { | ||
39 | {IWM_DM_BOOT, "boot"}, | ||
40 | {IWM_DM_FW, "fw"}, | ||
41 | {IWM_DM_SDIO, "sdio"}, | ||
42 | {IWM_DM_NTF, "ntf"}, | ||
43 | {IWM_DM_RX, "rx"}, | ||
44 | {IWM_DM_TX, "tx"}, | ||
45 | {IWM_DM_MLME, "mlme"}, | ||
46 | {IWM_DM_CMD, "cmd"}, | ||
47 | {IWM_DM_WEXT, "wext"}, | ||
48 | }; | ||
49 | |||
50 | #define add_dbg_module(dbg, name, id, initlevel) \ | ||
51 | do { \ | ||
52 | dbg.dbg_module[id] = (initlevel); \ | ||
53 | dbg.dbg_module_dentries[id] = \ | ||
54 | debugfs_create_x8(name, 0600, \ | ||
55 | dbg.dbgdir, \ | ||
56 | &(dbg.dbg_module[id])); \ | ||
57 | } while (0) | ||
58 | |||
59 | static int iwm_debugfs_u32_read(void *data, u64 *val) | ||
60 | { | ||
61 | struct iwm_priv *iwm = data; | ||
62 | |||
63 | *val = iwm->dbg.dbg_level; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int iwm_debugfs_dbg_level_write(void *data, u64 val) | ||
68 | { | ||
69 | struct iwm_priv *iwm = data; | ||
70 | int i; | ||
71 | |||
72 | iwm->dbg.dbg_level = val; | ||
73 | |||
74 | for (i = 0; i < __IWM_DM_NR; i++) | ||
75 | iwm->dbg.dbg_module[i] = val; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level, | ||
80 | iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write, | ||
81 | "%llu\n"); | ||
82 | |||
83 | static int iwm_debugfs_dbg_modules_write(void *data, u64 val) | ||
84 | { | ||
85 | struct iwm_priv *iwm = data; | ||
86 | int i, bit; | ||
87 | |||
88 | iwm->dbg.dbg_modules = val; | ||
89 | |||
90 | for (i = 0; i < __IWM_DM_NR; i++) | ||
91 | iwm->dbg.dbg_module[i] = 0; | ||
92 | |||
93 | for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) | ||
94 | iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, | ||
99 | iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, | ||
100 | "%llu\n"); | ||
101 | |||
102 | |||
103 | static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, | ||
104 | size_t count, loff_t *ppos) | ||
105 | { | ||
106 | struct iwm_priv *iwm = filp->private_data; | ||
107 | char *buf; | ||
108 | int i, buf_len = 4096; | ||
109 | size_t len = 0; | ||
110 | ssize_t ret; | ||
111 | |||
112 | if (*ppos != 0) | ||
113 | return 0; | ||
114 | if (count < sizeof(buf)) | ||
115 | return -ENOSPC; | ||
116 | |||
117 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
118 | if (!buf) | ||
119 | return -ENOMEM; | ||
120 | |||
121 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
122 | struct iwm_tx_queue *txq = &iwm->txq[i]; | ||
123 | struct sk_buff *skb; | ||
124 | int j; | ||
125 | unsigned long flags; | ||
126 | |||
127 | spin_lock_irqsave(&txq->queue.lock, flags); | ||
128 | |||
129 | skb = (struct sk_buff *)&txq->queue; | ||
130 | |||
131 | len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i); | ||
132 | len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n", | ||
133 | __netif_subqueue_stopped(iwm_to_ndev(iwm), | ||
134 | txq->id)); | ||
135 | len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n", | ||
136 | txq->concat_count); | ||
137 | len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n", | ||
138 | skb_queue_len(&txq->queue)); | ||
139 | for (j = 0; j < skb_queue_len(&txq->queue); j++) { | ||
140 | struct iwm_tx_info *tx_info; | ||
141 | |||
142 | skb = skb->next; | ||
143 | tx_info = skb_to_tx_info(skb); | ||
144 | |||
145 | len += snprintf(buf + len, buf_len - len, | ||
146 | "\tSKB #%d\n", j); | ||
147 | len += snprintf(buf + len, buf_len - len, | ||
148 | "\t\tsta: %d\n", tx_info->sta); | ||
149 | len += snprintf(buf + len, buf_len - len, | ||
150 | "\t\tcolor: %d\n", tx_info->color); | ||
151 | len += snprintf(buf + len, buf_len - len, | ||
152 | "\t\ttid: %d\n", tx_info->tid); | ||
153 | } | ||
154 | |||
155 | spin_unlock_irqrestore(&txq->queue.lock, flags); | ||
156 | |||
157 | spin_lock_irqsave(&txq->stopped_queue.lock, flags); | ||
158 | |||
159 | len += snprintf(buf + len, buf_len - len, | ||
160 | "\tStopped Queue len: %d\n", | ||
161 | skb_queue_len(&txq->stopped_queue)); | ||
162 | for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) { | ||
163 | struct iwm_tx_info *tx_info; | ||
164 | |||
165 | skb = skb->next; | ||
166 | tx_info = skb_to_tx_info(skb); | ||
167 | |||
168 | len += snprintf(buf + len, buf_len - len, | ||
169 | "\tSKB #%d\n", j); | ||
170 | len += snprintf(buf + len, buf_len - len, | ||
171 | "\t\tsta: %d\n", tx_info->sta); | ||
172 | len += snprintf(buf + len, buf_len - len, | ||
173 | "\t\tcolor: %d\n", tx_info->color); | ||
174 | len += snprintf(buf + len, buf_len - len, | ||
175 | "\t\ttid: %d\n", tx_info->tid); | ||
176 | } | ||
177 | |||
178 | spin_unlock_irqrestore(&txq->stopped_queue.lock, flags); | ||
179 | } | ||
180 | |||
181 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
182 | kfree(buf); | ||
183 | |||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static ssize_t iwm_debugfs_tx_credit_read(struct file *filp, | ||
188 | char __user *buffer, | ||
189 | size_t count, loff_t *ppos) | ||
190 | { | ||
191 | struct iwm_priv *iwm = filp->private_data; | ||
192 | struct iwm_tx_credit *credit = &iwm->tx_credit; | ||
193 | char *buf; | ||
194 | int i, buf_len = 4096; | ||
195 | size_t len = 0; | ||
196 | ssize_t ret; | ||
197 | |||
198 | if (*ppos != 0) | ||
199 | return 0; | ||
200 | if (count < sizeof(buf)) | ||
201 | return -ENOSPC; | ||
202 | |||
203 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
204 | if (!buf) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | len += snprintf(buf + len, buf_len - len, | ||
208 | "NR pools: %d\n", credit->pool_nr); | ||
209 | len += snprintf(buf + len, buf_len - len, | ||
210 | "pools map: 0x%lx\n", credit->full_pools_map); | ||
211 | |||
212 | len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n"); | ||
213 | for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) { | ||
214 | len += snprintf(buf + len, buf_len - len, | ||
215 | "pools entry #%d\n", i); | ||
216 | len += snprintf(buf + len, buf_len - len, | ||
217 | "\tid: %d\n", | ||
218 | credit->pools[i].id); | ||
219 | len += snprintf(buf + len, buf_len - len, | ||
220 | "\tsid: %d\n", | ||
221 | credit->pools[i].sid); | ||
222 | len += snprintf(buf + len, buf_len - len, | ||
223 | "\tmin_pages: %d\n", | ||
224 | credit->pools[i].min_pages); | ||
225 | len += snprintf(buf + len, buf_len - len, | ||
226 | "\tmax_pages: %d\n", | ||
227 | credit->pools[i].max_pages); | ||
228 | len += snprintf(buf + len, buf_len - len, | ||
229 | "\talloc_pages: %d\n", | ||
230 | credit->pools[i].alloc_pages); | ||
231 | len += snprintf(buf + len, buf_len - len, | ||
232 | "\tfreed_pages: %d\n", | ||
233 | credit->pools[i].total_freed_pages); | ||
234 | } | ||
235 | |||
236 | len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n"); | ||
237 | for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) { | ||
238 | len += snprintf(buf + len, buf_len - len, | ||
239 | "spools entry #%d\n", i); | ||
240 | len += snprintf(buf + len, buf_len - len, | ||
241 | "\tid: %d\n", | ||
242 | credit->spools[i].id); | ||
243 | len += snprintf(buf + len, buf_len - len, | ||
244 | "\tmax_pages: %d\n", | ||
245 | credit->spools[i].max_pages); | ||
246 | len += snprintf(buf + len, buf_len - len, | ||
247 | "\talloc_pages: %d\n", | ||
248 | credit->spools[i].alloc_pages); | ||
249 | |||
250 | } | ||
251 | |||
252 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
253 | kfree(buf); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, | ||
259 | char __user *buffer, | ||
260 | size_t count, loff_t *ppos) | ||
261 | { | ||
262 | struct iwm_priv *iwm = filp->private_data; | ||
263 | struct iwm_rx_ticket_node *ticket; | ||
264 | char *buf; | ||
265 | int buf_len = 4096, i; | ||
266 | size_t len = 0; | ||
267 | ssize_t ret; | ||
268 | |||
269 | if (*ppos != 0) | ||
270 | return 0; | ||
271 | if (count < sizeof(buf)) | ||
272 | return -ENOSPC; | ||
273 | |||
274 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
275 | if (!buf) | ||
276 | return -ENOMEM; | ||
277 | |||
278 | spin_lock(&iwm->ticket_lock); | ||
279 | list_for_each_entry(ticket, &iwm->rx_tickets, node) { | ||
280 | len += snprintf(buf + len, buf_len - len, "Ticket #%d\n", | ||
281 | ticket->ticket->id); | ||
282 | len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n", | ||
283 | ticket->ticket->action); | ||
284 | len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n", | ||
285 | ticket->ticket->flags); | ||
286 | } | ||
287 | spin_unlock(&iwm->ticket_lock); | ||
288 | |||
289 | for (i = 0; i < IWM_RX_ID_HASH; i++) { | ||
290 | struct iwm_rx_packet *packet; | ||
291 | struct list_head *pkt_list = &iwm->rx_packets[i]; | ||
292 | |||
293 | if (!list_empty(pkt_list)) { | ||
294 | len += snprintf(buf + len, buf_len - len, | ||
295 | "Packet hash #%d\n", i); | ||
296 | spin_lock(&iwm->packet_lock[i]); | ||
297 | list_for_each_entry(packet, pkt_list, node) { | ||
298 | len += snprintf(buf + len, buf_len - len, | ||
299 | "\tPacket id: %d\n", | ||
300 | packet->id); | ||
301 | len += snprintf(buf + len, buf_len - len, | ||
302 | "\tPacket length: %lu\n", | ||
303 | packet->pkt_size); | ||
304 | } | ||
305 | spin_unlock(&iwm->packet_lock[i]); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
310 | kfree(buf); | ||
311 | |||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | static ssize_t iwm_debugfs_fw_err_read(struct file *filp, | ||
316 | char __user *buffer, | ||
317 | size_t count, loff_t *ppos) | ||
318 | { | ||
319 | |||
320 | struct iwm_priv *iwm = filp->private_data; | ||
321 | char buf[512]; | ||
322 | int buf_len = 512; | ||
323 | size_t len = 0; | ||
324 | |||
325 | if (*ppos != 0) | ||
326 | return 0; | ||
327 | if (count < sizeof(buf)) | ||
328 | return -ENOSPC; | ||
329 | |||
330 | if (!iwm->last_fw_err) | ||
331 | return -ENOMEM; | ||
332 | |||
333 | if (iwm->last_fw_err->line_num == 0) | ||
334 | goto out; | ||
335 | |||
336 | len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n", | ||
337 | (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) | ||
338 | ? 'L' : 'U'); | ||
339 | len += snprintf(buf + len, buf_len - len, | ||
340 | "\tCategory: %d\n", | ||
341 | le32_to_cpu(iwm->last_fw_err->category)); | ||
342 | |||
343 | len += snprintf(buf + len, buf_len - len, | ||
344 | "\tStatus: 0x%x\n", | ||
345 | le32_to_cpu(iwm->last_fw_err->status)); | ||
346 | |||
347 | len += snprintf(buf + len, buf_len - len, | ||
348 | "\tPC: 0x%x\n", | ||
349 | le32_to_cpu(iwm->last_fw_err->pc)); | ||
350 | |||
351 | len += snprintf(buf + len, buf_len - len, | ||
352 | "\tblink1: %d\n", | ||
353 | le32_to_cpu(iwm->last_fw_err->blink1)); | ||
354 | |||
355 | len += snprintf(buf + len, buf_len - len, | ||
356 | "\tblink2: %d\n", | ||
357 | le32_to_cpu(iwm->last_fw_err->blink2)); | ||
358 | |||
359 | len += snprintf(buf + len, buf_len - len, | ||
360 | "\tilink1: %d\n", | ||
361 | le32_to_cpu(iwm->last_fw_err->ilink1)); | ||
362 | |||
363 | len += snprintf(buf + len, buf_len - len, | ||
364 | "\tilink2: %d\n", | ||
365 | le32_to_cpu(iwm->last_fw_err->ilink2)); | ||
366 | |||
367 | len += snprintf(buf + len, buf_len - len, | ||
368 | "\tData1: 0x%x\n", | ||
369 | le32_to_cpu(iwm->last_fw_err->data1)); | ||
370 | |||
371 | len += snprintf(buf + len, buf_len - len, | ||
372 | "\tData2: 0x%x\n", | ||
373 | le32_to_cpu(iwm->last_fw_err->data2)); | ||
374 | |||
375 | len += snprintf(buf + len, buf_len - len, | ||
376 | "\tLine number: %d\n", | ||
377 | le32_to_cpu(iwm->last_fw_err->line_num)); | ||
378 | |||
379 | len += snprintf(buf + len, buf_len - len, | ||
380 | "\tUMAC status: 0x%x\n", | ||
381 | le32_to_cpu(iwm->last_fw_err->umac_status)); | ||
382 | |||
383 | len += snprintf(buf + len, buf_len - len, | ||
384 | "\tLMAC status: 0x%x\n", | ||
385 | le32_to_cpu(iwm->last_fw_err->lmac_status)); | ||
386 | |||
387 | len += snprintf(buf + len, buf_len - len, | ||
388 | "\tSDIO status: 0x%x\n", | ||
389 | le32_to_cpu(iwm->last_fw_err->sdio_status)); | ||
390 | |||
391 | out: | ||
392 | |||
393 | return simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
394 | } | ||
395 | |||
396 | static const struct file_operations iwm_debugfs_txq_fops = { | ||
397 | .owner = THIS_MODULE, | ||
398 | .open = simple_open, | ||
399 | .read = iwm_debugfs_txq_read, | ||
400 | .llseek = default_llseek, | ||
401 | }; | ||
402 | |||
403 | static const struct file_operations iwm_debugfs_tx_credit_fops = { | ||
404 | .owner = THIS_MODULE, | ||
405 | .open = simple_open, | ||
406 | .read = iwm_debugfs_tx_credit_read, | ||
407 | .llseek = default_llseek, | ||
408 | }; | ||
409 | |||
410 | static const struct file_operations iwm_debugfs_rx_ticket_fops = { | ||
411 | .owner = THIS_MODULE, | ||
412 | .open = simple_open, | ||
413 | .read = iwm_debugfs_rx_ticket_read, | ||
414 | .llseek = default_llseek, | ||
415 | }; | ||
416 | |||
417 | static const struct file_operations iwm_debugfs_fw_err_fops = { | ||
418 | .owner = THIS_MODULE, | ||
419 | .open = simple_open, | ||
420 | .read = iwm_debugfs_fw_err_read, | ||
421 | .llseek = default_llseek, | ||
422 | }; | ||
423 | |||
424 | void iwm_debugfs_init(struct iwm_priv *iwm) | ||
425 | { | ||
426 | int i; | ||
427 | |||
428 | iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
429 | iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)), | ||
430 | iwm->dbg.rootdir); | ||
431 | iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir); | ||
432 | iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir); | ||
433 | iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir); | ||
434 | iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir); | ||
435 | if (iwm->bus_ops->debugfs_init) | ||
436 | iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir); | ||
437 | |||
438 | iwm->dbg.dbg_level = IWM_DL_NONE; | ||
439 | iwm->dbg.dbg_level_dentry = | ||
440 | debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm, | ||
441 | &fops_iwm_dbg_level); | ||
442 | |||
443 | iwm->dbg.dbg_modules = IWM_DM_DEFAULT; | ||
444 | iwm->dbg.dbg_modules_dentry = | ||
445 | debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm, | ||
446 | &fops_iwm_dbg_modules); | ||
447 | |||
448 | for (i = 0; i < __IWM_DM_NR; i++) | ||
449 | add_dbg_module(iwm->dbg, iwm_debug_module[i].name, | ||
450 | iwm_debug_module[i].id, IWM_DL_DEFAULT); | ||
451 | |||
452 | iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200, | ||
453 | iwm->dbg.txdir, iwm, | ||
454 | &iwm_debugfs_txq_fops); | ||
455 | iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200, | ||
456 | iwm->dbg.txdir, iwm, | ||
457 | &iwm_debugfs_tx_credit_fops); | ||
458 | iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200, | ||
459 | iwm->dbg.rxdir, iwm, | ||
460 | &iwm_debugfs_rx_ticket_fops); | ||
461 | iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200, | ||
462 | iwm->dbg.dbgdir, iwm, | ||
463 | &iwm_debugfs_fw_err_fops); | ||
464 | } | ||
465 | |||
466 | void iwm_debugfs_exit(struct iwm_priv *iwm) | ||
467 | { | ||
468 | int i; | ||
469 | |||
470 | for (i = 0; i < __IWM_DM_NR; i++) | ||
471 | debugfs_remove(iwm->dbg.dbg_module_dentries[i]); | ||
472 | |||
473 | debugfs_remove(iwm->dbg.dbg_modules_dentry); | ||
474 | debugfs_remove(iwm->dbg.dbg_level_dentry); | ||
475 | debugfs_remove(iwm->dbg.txq_dentry); | ||
476 | debugfs_remove(iwm->dbg.tx_credit_dentry); | ||
477 | debugfs_remove(iwm->dbg.rx_ticket_dentry); | ||
478 | debugfs_remove(iwm->dbg.fw_err_dentry); | ||
479 | if (iwm->bus_ops->debugfs_exit) | ||
480 | iwm->bus_ops->debugfs_exit(iwm); | ||
481 | |||
482 | debugfs_remove(iwm->dbg.busdir); | ||
483 | debugfs_remove(iwm->dbg.dbgdir); | ||
484 | debugfs_remove(iwm->dbg.txdir); | ||
485 | debugfs_remove(iwm->dbg.rxdir); | ||
486 | debugfs_remove(iwm->dbg.devdir); | ||
487 | debugfs_remove(iwm->dbg.rootdir); | ||
488 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c deleted file mode 100644 index e80e776b74f7..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ /dev/null | |||
@@ -1,234 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/slab.h> | ||
41 | |||
42 | #include "iwm.h" | ||
43 | #include "umac.h" | ||
44 | #include "commands.h" | ||
45 | #include "eeprom.h" | ||
46 | |||
47 | static struct iwm_eeprom_entry eeprom_map[] = { | ||
48 | [IWM_EEPROM_SIG] = | ||
49 | {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN}, | ||
50 | |||
51 | [IWM_EEPROM_VERSION] = | ||
52 | {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN}, | ||
53 | |||
54 | [IWM_EEPROM_OEM_HW_VERSION] = | ||
55 | {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF, | ||
56 | IWM_EEPROM_OEM_HW_VERSION_LEN}, | ||
57 | |||
58 | [IWM_EEPROM_MAC_VERSION] = | ||
59 | {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN}, | ||
60 | |||
61 | [IWM_EEPROM_CARD_ID] = | ||
62 | {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN}, | ||
63 | |||
64 | [IWM_EEPROM_RADIO_CONF] = | ||
65 | {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN}, | ||
66 | |||
67 | [IWM_EEPROM_SKU_CAP] = | ||
68 | {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, | ||
69 | |||
70 | [IWM_EEPROM_FAT_CHANNELS_CAP] = | ||
71 | {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF, | ||
72 | IWM_EEPROM_FAT_CHANNELS_CAP_LEN}, | ||
73 | |||
74 | [IWM_EEPROM_CALIB_RXIQ_OFFSET] = | ||
75 | {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, | ||
76 | |||
77 | [IWM_EEPROM_CALIB_RXIQ] = | ||
78 | {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN}, | ||
79 | }; | ||
80 | |||
81 | |||
82 | static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id) | ||
83 | { | ||
84 | int ret; | ||
85 | u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0; | ||
86 | u32 addr; | ||
87 | struct iwm_udma_wifi_cmd udma_cmd; | ||
88 | struct iwm_umac_cmd umac_cmd; | ||
89 | struct iwm_umac_cmd_eeprom_proxy eeprom_cmd; | ||
90 | |||
91 | if (eeprom_id > (IWM_EEPROM_LAST - 1)) | ||
92 | return -EINVAL; | ||
93 | |||
94 | entry_size = eeprom_map[eeprom_id].length; | ||
95 | |||
96 | if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) { | ||
97 | /* indirect data */ | ||
98 | u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA + | ||
99 | IWM_EEPROM_INDIRECT_OFFSET; | ||
100 | |||
101 | eeprom_map[eeprom_id].offset = | ||
102 | *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1; | ||
103 | } | ||
104 | |||
105 | addr = eeprom_map[eeprom_id].offset; | ||
106 | |||
107 | udma_cmd.eop = 1; | ||
108 | udma_cmd.credit_group = 0x4; | ||
109 | udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD; | ||
110 | udma_cmd.lmac_offset = 0; | ||
111 | |||
112 | umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY; | ||
113 | umac_cmd.resp = 1; | ||
114 | |||
115 | while (entry_size > 0) { | ||
116 | chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN); | ||
117 | |||
118 | eeprom_cmd.hdr.type = | ||
119 | cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ); | ||
120 | eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset); | ||
121 | eeprom_cmd.hdr.len = cpu_to_le32(chunk_size); | ||
122 | |||
123 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, | ||
124 | &umac_cmd, &eeprom_cmd, | ||
125 | sizeof(struct iwm_umac_cmd_eeprom_proxy)); | ||
126 | if (ret < 0) { | ||
127 | IWM_ERR(iwm, "Couldn't read eeprom\n"); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY, | ||
132 | IWM_SRC_UMAC, 2*HZ); | ||
133 | if (ret < 0) { | ||
134 | IWM_ERR(iwm, "Did not get any eeprom answer\n"); | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | data_offset += chunk_size; | ||
139 | addr_offset += chunk_size; | ||
140 | entry_size -= chunk_size; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) | ||
147 | { | ||
148 | if (!iwm->eeprom) | ||
149 | return ERR_PTR(-ENODEV); | ||
150 | |||
151 | return iwm->eeprom + eeprom_map[eeprom_id].offset; | ||
152 | } | ||
153 | |||
154 | int iwm_eeprom_fat_channels(struct iwm_priv *iwm) | ||
155 | { | ||
156 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
157 | struct ieee80211_supported_band *band; | ||
158 | u16 *channels, i; | ||
159 | |||
160 | channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP); | ||
161 | if (IS_ERR(channels)) | ||
162 | return PTR_ERR(channels); | ||
163 | |||
164 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
165 | band->ht_cap.ht_supported = true; | ||
166 | |||
167 | for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++) | ||
168 | if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) | ||
169 | band->ht_cap.ht_supported = false; | ||
170 | |||
171 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
172 | band->ht_cap.ht_supported = true; | ||
173 | for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++) | ||
174 | if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) | ||
175 | band->ht_cap.ht_supported = false; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm) | ||
181 | { | ||
182 | u16 sku_cap; | ||
183 | u32 wireless_mode = 0; | ||
184 | |||
185 | sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)); | ||
186 | |||
187 | if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ) | ||
188 | wireless_mode |= WIRELESS_MODE_11G; | ||
189 | |||
190 | if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ) | ||
191 | wireless_mode |= WIRELESS_MODE_11A; | ||
192 | |||
193 | if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE) | ||
194 | wireless_mode |= WIRELESS_MODE_11N; | ||
195 | |||
196 | return wireless_mode; | ||
197 | } | ||
198 | |||
199 | |||
200 | int iwm_eeprom_init(struct iwm_priv *iwm) | ||
201 | { | ||
202 | int i, ret = 0; | ||
203 | char name[32]; | ||
204 | |||
205 | iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL); | ||
206 | if (!iwm->eeprom) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { | ||
210 | ret = iwm_eeprom_read(iwm, i); | ||
211 | if (ret < 0) { | ||
212 | IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", | ||
213 | i, eeprom_map[i].name); | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n"); | ||
219 | for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { | ||
220 | memset(name, 0, 32); | ||
221 | sprintf(name, "%s: ", eeprom_map[i].name); | ||
222 | |||
223 | IWM_HEXDUMP(iwm, DBG, BOOT, name, | ||
224 | iwm->eeprom + eeprom_map[i].offset, | ||
225 | eeprom_map[i].length); | ||
226 | } | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | void iwm_eeprom_exit(struct iwm_priv *iwm) | ||
232 | { | ||
233 | kfree(iwm->eeprom); | ||
234 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h deleted file mode 100644 index 4e3a3fdab0d3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.h +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_EEPROM_H__ | ||
40 | #define __IWM_EEPROM_H__ | ||
41 | |||
42 | enum { | ||
43 | IWM_EEPROM_SIG = 0, | ||
44 | IWM_EEPROM_FIRST = IWM_EEPROM_SIG, | ||
45 | IWM_EEPROM_VERSION, | ||
46 | IWM_EEPROM_OEM_HW_VERSION, | ||
47 | IWM_EEPROM_MAC_VERSION, | ||
48 | IWM_EEPROM_CARD_ID, | ||
49 | IWM_EEPROM_RADIO_CONF, | ||
50 | IWM_EEPROM_SKU_CAP, | ||
51 | IWM_EEPROM_FAT_CHANNELS_CAP, | ||
52 | |||
53 | IWM_EEPROM_INDIRECT_OFFSET, | ||
54 | IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, | ||
55 | |||
56 | IWM_EEPROM_INDIRECT_DATA, | ||
57 | IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA, | ||
58 | |||
59 | IWM_EEPROM_LAST, | ||
60 | }; | ||
61 | |||
62 | #define IWM_EEPROM_SIG_OFF 0x00 | ||
63 | #define IWM_EEPROM_VERSION_OFF (0x54 << 1) | ||
64 | #define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) | ||
65 | #define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) | ||
66 | #define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) | ||
67 | #define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) | ||
68 | #define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) | ||
69 | #define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) | ||
70 | #define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1) | ||
71 | |||
72 | #define IWM_EEPROM_SIG_LEN 4 | ||
73 | #define IWM_EEPROM_VERSION_LEN 2 | ||
74 | #define IWM_EEPROM_OEM_HW_VERSION_LEN 2 | ||
75 | #define IWM_EEPROM_MAC_VERSION_LEN 1 | ||
76 | #define IWM_EEPROM_CARD_ID_LEN 2 | ||
77 | #define IWM_EEPROM_RADIO_CONF_LEN 2 | ||
78 | #define IWM_EEPROM_SKU_CAP_LEN 2 | ||
79 | #define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40 | ||
80 | #define IWM_EEPROM_INDIRECT_LEN 2 | ||
81 | |||
82 | #define IWM_MAX_EEPROM_DATA_LEN 240 | ||
83 | #define IWM_EEPROM_LEN 0x800 | ||
84 | |||
85 | #define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610 | ||
86 | #define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700 | ||
87 | #define IWM_EEPROM_CURRENT_VERSION 0x0612 | ||
88 | |||
89 | #define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4) | ||
90 | #define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) | ||
91 | #define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) | ||
92 | |||
93 | #define IWM_EEPROM_FAT_CHANNELS 20 | ||
94 | /* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */ | ||
95 | #define IWM_EEPROM_FAT_CHANNELS_24 9 | ||
96 | /* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */ | ||
97 | #define IWM_EEPROM_FAT_CHANNELS_52 11 | ||
98 | |||
99 | #define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0) | ||
100 | |||
101 | enum { | ||
102 | IWM_EEPROM_CALIB_CAL_HDR, | ||
103 | IWM_EEPROM_CALIB_TX_POWER, | ||
104 | IWM_EEPROM_CALIB_XTAL, | ||
105 | IWM_EEPROM_CALIB_TEMPERATURE, | ||
106 | IWM_EEPROM_CALIB_RX_BB_FILTER, | ||
107 | IWM_EEPROM_CALIB_RX_IQ, | ||
108 | IWM_EEPROM_CALIB_MAX, | ||
109 | }; | ||
110 | |||
111 | #define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \ | ||
112 | (IWM_EEPROM_CALIB_RX_IQ << 1)) | ||
113 | #define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq) | ||
114 | |||
115 | struct iwm_eeprom_entry { | ||
116 | char *name; | ||
117 | u32 offset; | ||
118 | u32 length; | ||
119 | }; | ||
120 | |||
121 | int iwm_eeprom_init(struct iwm_priv *iwm); | ||
122 | void iwm_eeprom_exit(struct iwm_priv *iwm); | ||
123 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); | ||
124 | int iwm_eeprom_fat_channels(struct iwm_priv *iwm); | ||
125 | u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm); | ||
126 | |||
127 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c deleted file mode 100644 index 6f1afe6bbc8c..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ /dev/null | |||
@@ -1,416 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/firmware.h> | ||
41 | |||
42 | #include "iwm.h" | ||
43 | #include "bus.h" | ||
44 | #include "hal.h" | ||
45 | #include "umac.h" | ||
46 | #include "debug.h" | ||
47 | #include "fw.h" | ||
48 | #include "commands.h" | ||
49 | |||
50 | static const char fw_barker[] = "*WESTOPFORNOONE*"; | ||
51 | |||
52 | /* | ||
53 | * @op_code: Op code we're looking for. | ||
54 | * @index: There can be several instances of the same opcode within | ||
55 | * the firmware. Index specifies which one we're looking for. | ||
56 | */ | ||
57 | static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, | ||
58 | u16 op_code, u32 index) | ||
59 | { | ||
60 | int offset = -EINVAL, fw_offset; | ||
61 | u32 op_index = 0; | ||
62 | const u8 *fw_ptr; | ||
63 | struct iwm_fw_hdr_rec *rec; | ||
64 | |||
65 | fw_offset = 0; | ||
66 | fw_ptr = fw->data; | ||
67 | |||
68 | /* We first need to look for the firmware barker */ | ||
69 | if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) { | ||
70 | IWM_ERR(iwm, "No barker string in this FW\n"); | ||
71 | return -EINVAL; | ||
72 | } | ||
73 | |||
74 | if (fw->size < IWM_HDR_LEN) { | ||
75 | IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | fw_offset += IWM_HDR_BARKER_LEN; | ||
80 | |||
81 | while (fw_offset < fw->size) { | ||
82 | rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset); | ||
83 | |||
84 | IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n", | ||
85 | rec->op_code, rec->len, fw_offset); | ||
86 | |||
87 | if (rec->op_code == IWM_HDR_REC_OP_INVALID) { | ||
88 | IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n"); | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | if (rec->op_code == op_code) { | ||
93 | if (op_index == index) { | ||
94 | fw_offset += sizeof(struct iwm_fw_hdr_rec); | ||
95 | offset = fw_offset; | ||
96 | goto out; | ||
97 | } | ||
98 | op_index++; | ||
99 | } | ||
100 | |||
101 | fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len; | ||
102 | } | ||
103 | |||
104 | out: | ||
105 | return offset; | ||
106 | } | ||
107 | |||
108 | static int iwm_load_firmware_chunk(struct iwm_priv *iwm, | ||
109 | const struct firmware *fw, | ||
110 | struct iwm_fw_img_desc *img_desc) | ||
111 | { | ||
112 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
113 | u32 chunk_size; | ||
114 | const u8 *chunk_ptr; | ||
115 | int ret = 0; | ||
116 | |||
117 | IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n", | ||
118 | img_desc->length, img_desc->address); | ||
119 | |||
120 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
121 | target_cmd.handle_by_hw = 1; | ||
122 | target_cmd.op2 = 0; | ||
123 | target_cmd.resp = 0; | ||
124 | target_cmd.eop = 1; | ||
125 | |||
126 | chunk_size = img_desc->length; | ||
127 | chunk_ptr = fw->data + img_desc->offset; | ||
128 | |||
129 | while (chunk_size > 0) { | ||
130 | u32 tmp_chunk_size; | ||
131 | |||
132 | tmp_chunk_size = min_t(u32, chunk_size, | ||
133 | IWM_MAX_NONWIFI_CMD_BUFF_SIZE); | ||
134 | |||
135 | target_cmd.addr = cpu_to_le32(img_desc->address + | ||
136 | (chunk_ptr - fw->data - img_desc->offset)); | ||
137 | target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size); | ||
138 | |||
139 | IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n", | ||
140 | tmp_chunk_size, target_cmd.addr); | ||
141 | |||
142 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr); | ||
143 | if (ret < 0) { | ||
144 | IWM_ERR(iwm, "Couldn't load FW chunk\n"); | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | chunk_size -= tmp_chunk_size; | ||
149 | chunk_ptr += tmp_chunk_size; | ||
150 | } | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | /* | ||
155 | * To load a fw image to the target, we basically go through the | ||
156 | * fw, looking for OP_MEM_DESC records. Once we found one, we | ||
157 | * pass it to iwm_load_firmware_chunk(). | ||
158 | * The OP_MEM_DESC records contain the actuall memory chunk to be | ||
159 | * sent, but also the destination address. | ||
160 | */ | ||
161 | static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) | ||
162 | { | ||
163 | const struct firmware *fw; | ||
164 | struct iwm_fw_img_desc *img_desc; | ||
165 | struct iwm_fw_img_ver *ver; | ||
166 | int ret = 0, fw_offset; | ||
167 | u32 opcode_idx = 0, build_date; | ||
168 | char *build_tag; | ||
169 | |||
170 | ret = request_firmware(&fw, img_name, iwm_to_dev(iwm)); | ||
171 | if (ret) { | ||
172 | IWM_ERR(iwm, "Request firmware failed"); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name); | ||
177 | |||
178 | while (1) { | ||
179 | fw_offset = iwm_fw_op_offset(iwm, fw, | ||
180 | IWM_HDR_REC_OP_MEM_DESC, | ||
181 | opcode_idx); | ||
182 | if (fw_offset < 0) | ||
183 | break; | ||
184 | |||
185 | img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset); | ||
186 | ret = iwm_load_firmware_chunk(iwm, fw, img_desc); | ||
187 | if (ret < 0) | ||
188 | goto err_release_fw; | ||
189 | opcode_idx++; | ||
190 | } | ||
191 | |||
192 | /* Read firmware version */ | ||
193 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); | ||
194 | if (fw_offset < 0) | ||
195 | goto err_release_fw; | ||
196 | |||
197 | ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset); | ||
198 | |||
199 | /* Read build tag */ | ||
200 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0); | ||
201 | if (fw_offset < 0) | ||
202 | goto err_release_fw; | ||
203 | |||
204 | build_tag = (char *)(fw->data + fw_offset); | ||
205 | |||
206 | /* Read build date */ | ||
207 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0); | ||
208 | if (fw_offset < 0) | ||
209 | goto err_release_fw; | ||
210 | |||
211 | build_date = *(u32 *)(fw->data + fw_offset); | ||
212 | |||
213 | IWM_INFO(iwm, "%s:\n", img_name); | ||
214 | IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor); | ||
215 | IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag); | ||
216 | IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n", | ||
217 | IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), | ||
218 | IWM_BUILD_DAY(build_date)); | ||
219 | |||
220 | if (!strcmp(img_name, iwm->bus_ops->umac_name)) | ||
221 | sprintf(iwm->umac_version, "%02X.%02X", | ||
222 | ver->major, ver->minor); | ||
223 | |||
224 | if (!strcmp(img_name, iwm->bus_ops->lmac_name)) | ||
225 | sprintf(iwm->lmac_version, "%02X.%02X", | ||
226 | ver->major, ver->minor); | ||
227 | |||
228 | err_release_fw: | ||
229 | release_firmware(fw); | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int iwm_load_umac(struct iwm_priv *iwm) | ||
235 | { | ||
236 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
237 | int ret; | ||
238 | |||
239 | ret = iwm_load_img(iwm, iwm->bus_ops->umac_name); | ||
240 | if (ret < 0) | ||
241 | return ret; | ||
242 | |||
243 | /* We've loaded the UMAC, we can tell the target to jump there */ | ||
244 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP; | ||
245 | target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR); | ||
246 | target_cmd.op1_sz = 0; | ||
247 | target_cmd.op2 = 0; | ||
248 | target_cmd.handle_by_hw = 0; | ||
249 | target_cmd.resp = 1 ; | ||
250 | target_cmd.eop = 1; | ||
251 | |||
252 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
253 | if (ret < 0) | ||
254 | IWM_ERR(iwm, "Couldn't send JMP command\n"); | ||
255 | |||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) | ||
260 | { | ||
261 | int ret; | ||
262 | |||
263 | ret = iwm_load_img(iwm, img_name); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | return iwm_send_umac_reset(iwm, | ||
268 | cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); | ||
269 | } | ||
270 | |||
271 | static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap, | ||
272 | unsigned long expected_bitmap, u8 rx_iq_cmd) | ||
273 | { | ||
274 | /* Read RX IQ calibration result from EEPROM */ | ||
275 | if (test_bit(rx_iq_cmd, &cfg_bitmap)) { | ||
276 | iwm_store_rxiq_calib_result(iwm); | ||
277 | set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); | ||
278 | } | ||
279 | |||
280 | iwm_send_prio_table(iwm); | ||
281 | iwm_send_init_calib_cfg(iwm, cfg_bitmap); | ||
282 | |||
283 | while (iwm->calib_done_map != expected_bitmap) { | ||
284 | if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, | ||
285 | IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) { | ||
286 | IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n"); | ||
287 | return -ETIMEDOUT; | ||
288 | } | ||
289 | |||
290 | IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " | ||
291 | "0x%lx, expected calibrations: 0x%lx\n", | ||
292 | iwm->calib_done_map, expected_bitmap); | ||
293 | } | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * We currently have to load 3 FWs: | ||
300 | * 1) The UMAC (Upper MAC). | ||
301 | * 2) The calibration LMAC (Lower MAC). | ||
302 | * We then send the calibration init command, so that the device can | ||
303 | * run a first calibration round. | ||
304 | * 3) The operational LMAC, which replaces the calibration one when it's | ||
305 | * done with the first calibration round. | ||
306 | * | ||
307 | * Once those 3 FWs have been loaded, we send the periodic calibration | ||
308 | * command, and then the device is available for regular 802.11 operations. | ||
309 | */ | ||
310 | int iwm_load_fw(struct iwm_priv *iwm) | ||
311 | { | ||
312 | unsigned long init_calib_map, periodic_calib_map; | ||
313 | unsigned long expected_calib_map; | ||
314 | int ret; | ||
315 | |||
316 | /* We first start downloading the UMAC */ | ||
317 | ret = iwm_load_umac(iwm); | ||
318 | if (ret < 0) { | ||
319 | IWM_ERR(iwm, "UMAC loading failed\n"); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | /* Handle UMAC_ALIVE notification */ | ||
324 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC, | ||
325 | WAIT_NOTIF_TIMEOUT); | ||
326 | if (ret) { | ||
327 | IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret); | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | /* UMAC is alive, we can download the calibration LMAC */ | ||
332 | ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name); | ||
333 | if (ret) { | ||
334 | IWM_ERR(iwm, "Calibration LMAC loading failed\n"); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | /* Handle UMAC_INIT_COMPLETE notification */ | ||
339 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, | ||
340 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
341 | if (ret) { | ||
342 | IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration " | ||
343 | "LMAC: %d\n", ret); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | /* Read EEPROM data */ | ||
348 | ret = iwm_eeprom_init(iwm); | ||
349 | if (ret < 0) { | ||
350 | IWM_ERR(iwm, "Couldn't init eeprom array\n"); | ||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; | ||
355 | expected_calib_map = iwm->conf.expected_calib_map & | ||
356 | IWM_CALIB_MAP_INIT_MSK; | ||
357 | periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); | ||
358 | |||
359 | ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map, | ||
360 | CALIB_CFG_RX_IQ_IDX); | ||
361 | if (ret < 0) { | ||
362 | /* Let's try the old way */ | ||
363 | ret = iwm_init_calib(iwm, expected_calib_map, | ||
364 | expected_calib_map, | ||
365 | PHY_CALIBRATE_RX_IQ_CMD); | ||
366 | if (ret < 0) { | ||
367 | IWM_ERR(iwm, "Calibration result timeout\n"); | ||
368 | goto out; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | /* Handle LMAC CALIBRATION_COMPLETE notification */ | ||
373 | ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION, | ||
374 | IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); | ||
375 | if (ret) { | ||
376 | IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n"); | ||
377 | goto out; | ||
378 | } | ||
379 | |||
380 | IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map); | ||
381 | |||
382 | iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1); | ||
383 | |||
384 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, | ||
385 | WAIT_NOTIF_TIMEOUT); | ||
386 | if (ret) { | ||
387 | IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); | ||
388 | goto out; | ||
389 | } | ||
390 | |||
391 | /* Download the operational LMAC */ | ||
392 | ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name); | ||
393 | if (ret) { | ||
394 | IWM_ERR(iwm, "LMAC loading failed\n"); | ||
395 | goto out; | ||
396 | } | ||
397 | |||
398 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, | ||
399 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
400 | if (ret) { | ||
401 | IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret); | ||
402 | goto out; | ||
403 | } | ||
404 | |||
405 | iwm_send_prio_table(iwm); | ||
406 | iwm_send_calib_results(iwm); | ||
407 | iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); | ||
408 | iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry, | ||
409 | iwm->conf.ct_kill_exit); | ||
410 | |||
411 | return 0; | ||
412 | |||
413 | out: | ||
414 | iwm_eeprom_exit(iwm); | ||
415 | return ret; | ||
416 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h deleted file mode 100644 index c70a3b40dad3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/fw.h +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_FW_H__ | ||
40 | #define __IWM_FW_H__ | ||
41 | |||
42 | /** | ||
43 | * struct iwm_fw_hdr_rec - An iwm firmware image is a | ||
44 | * concatenation of various records. Each of them is | ||
45 | * defined by an ID (aka op code), a length, and the | ||
46 | * actual data. | ||
47 | * @op_code: The record ID, see IWM_HDR_REC_OP_* | ||
48 | * | ||
49 | * @len: The record payload length | ||
50 | * | ||
51 | * @buf: The record payload | ||
52 | */ | ||
53 | struct iwm_fw_hdr_rec { | ||
54 | u16 op_code; | ||
55 | u16 len; | ||
56 | u8 buf[0]; | ||
57 | }; | ||
58 | |||
59 | /* Header's definitions */ | ||
60 | #define IWM_HDR_LEN (512) | ||
61 | #define IWM_HDR_BARKER_LEN (16) | ||
62 | |||
63 | /* Header's opcodes */ | ||
64 | #define IWM_HDR_REC_OP_INVALID (0x00) | ||
65 | #define IWM_HDR_REC_OP_BUILD_DATE (0x01) | ||
66 | #define IWM_HDR_REC_OP_BUILD_TAG (0x02) | ||
67 | #define IWM_HDR_REC_OP_SW_VER (0x03) | ||
68 | #define IWM_HDR_REC_OP_HW_SKU (0x04) | ||
69 | #define IWM_HDR_REC_OP_BUILD_OPT (0x05) | ||
70 | #define IWM_HDR_REC_OP_MEM_DESC (0x06) | ||
71 | #define IWM_HDR_REC_USERDEFS (0x07) | ||
72 | |||
73 | /* Header's records length (in bytes) */ | ||
74 | #define IWM_HDR_REC_LEN_BUILD_DATE (4) | ||
75 | #define IWM_HDR_REC_LEN_BUILD_TAG (64) | ||
76 | #define IWM_HDR_REC_LEN_SW_VER (4) | ||
77 | #define IWM_HDR_REC_LEN_HW_SKU (4) | ||
78 | #define IWM_HDR_REC_LEN_BUILD_OPT (4) | ||
79 | #define IWM_HDR_REC_LEN_MEM_DESC (12) | ||
80 | #define IWM_HDR_REC_LEN_USERDEF (64) | ||
81 | |||
82 | #define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff) | ||
83 | #define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff) | ||
84 | #define IWM_BUILD_DAY(date) (date & 0xff) | ||
85 | |||
86 | struct iwm_fw_img_desc { | ||
87 | u32 offset; | ||
88 | u32 address; | ||
89 | u32 length; | ||
90 | }; | ||
91 | |||
92 | struct iwm_fw_img_ver { | ||
93 | u8 minor; | ||
94 | u8 major; | ||
95 | u16 reserved; | ||
96 | }; | ||
97 | |||
98 | int iwm_load_fw(struct iwm_priv *iwm); | ||
99 | |||
100 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c deleted file mode 100644 index 1cabcb39643f..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ /dev/null | |||
@@ -1,470 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * Hardware Abstraction Layer for iwm. | ||
41 | * | ||
42 | * This file mostly defines an abstraction API for | ||
43 | * sending various commands to the target. | ||
44 | * | ||
45 | * We have 2 types of commands: wifi and non-wifi ones. | ||
46 | * | ||
47 | * - wifi commands: | ||
48 | * They are used for sending LMAC and UMAC commands, | ||
49 | * and thus are the most commonly used ones. | ||
50 | * There are 2 different wifi command types, the regular | ||
51 | * one and the LMAC one. The former is used to send | ||
52 | * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h) | ||
53 | * while the latter is used for sending commands to the | ||
54 | * LMAC. If you look at LMAC commands you'll se that they | ||
55 | * are actually regular iwlwifi target commands encapsulated | ||
56 | * into a special UMAC command called UMAC passthrough. | ||
57 | * This is due to the fact the host talks exclusively | ||
58 | * to the UMAC and so there needs to be a special UMAC | ||
59 | * command for talking to the LMAC. | ||
60 | * This is how a wifi command is laid out: | ||
61 | * ------------------------ | ||
62 | * | iwm_udma_out_wifi_hdr | | ||
63 | * ------------------------ | ||
64 | * | SW meta_data (32 bits) | | ||
65 | * ------------------------ | ||
66 | * | iwm_dev_cmd_hdr | | ||
67 | * ------------------------ | ||
68 | * | payload | | ||
69 | * | .... | | ||
70 | * | ||
71 | * - non-wifi, or general commands: | ||
72 | * Those commands are handled by the device's bootrom, | ||
73 | * and are typically sent when the UMAC and the LMAC | ||
74 | * are not yet available. | ||
75 | * * This is how a non-wifi command is laid out: | ||
76 | * --------------------------- | ||
77 | * | iwm_udma_out_nonwifi_hdr | | ||
78 | * --------------------------- | ||
79 | * | payload | | ||
80 | * | .... | | ||
81 | |||
82 | * | ||
83 | * All the commands start with a UDMA header, which is | ||
84 | * basically a 32 bits field. The 4 LSB there define | ||
85 | * an opcode that allows the target to differentiate | ||
86 | * between wifi (opcode is 0xf) and non-wifi commands | ||
87 | * (opcode is [0..0xe]). | ||
88 | * | ||
89 | * When a command (wifi or non-wifi) is supposed to receive | ||
90 | * an answer, we queue the command buffer. When we do receive | ||
91 | * a command response from the UMAC, we go through the list | ||
92 | * of pending command, and pass both the command and the answer | ||
93 | * to the rx handler. Each command is sent with a unique | ||
94 | * sequence id, and the answer is sent with the same one. This | ||
95 | * is how we're supposed to match an answer with its command. | ||
96 | * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi() | ||
97 | * for the implementation details. | ||
98 | */ | ||
99 | #include <linux/kernel.h> | ||
100 | #include <linux/netdevice.h> | ||
101 | #include <linux/slab.h> | ||
102 | |||
103 | #include "iwm.h" | ||
104 | #include "bus.h" | ||
105 | #include "hal.h" | ||
106 | #include "umac.h" | ||
107 | #include "debug.h" | ||
108 | #include "trace.h" | ||
109 | |||
110 | static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm, | ||
111 | struct iwm_nonwifi_cmd *cmd, | ||
112 | struct iwm_udma_nonwifi_cmd *udma_cmd) | ||
113 | { | ||
114 | INIT_LIST_HEAD(&cmd->pending); | ||
115 | |||
116 | spin_lock(&iwm->cmd_lock); | ||
117 | |||
118 | cmd->resp_received = 0; | ||
119 | |||
120 | cmd->seq_num = iwm->nonwifi_seq_num; | ||
121 | udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
122 | |||
123 | iwm->nonwifi_seq_num++; | ||
124 | iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; | ||
125 | |||
126 | if (udma_cmd->resp) | ||
127 | list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd); | ||
128 | |||
129 | spin_unlock(&iwm->cmd_lock); | ||
130 | |||
131 | cmd->buf.start = cmd->buf.payload; | ||
132 | cmd->buf.len = 0; | ||
133 | |||
134 | memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); | ||
135 | |||
136 | return cmd->seq_num; | ||
137 | } | ||
138 | |||
139 | u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) | ||
140 | { | ||
141 | u16 seq_num = iwm->wifi_seq_num; | ||
142 | |||
143 | iwm->wifi_seq_num++; | ||
144 | iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX; | ||
145 | |||
146 | return seq_num; | ||
147 | } | ||
148 | |||
149 | static void iwm_wifi_cmd_init(struct iwm_priv *iwm, | ||
150 | struct iwm_wifi_cmd *cmd, | ||
151 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
152 | struct iwm_umac_cmd *umac_cmd, | ||
153 | struct iwm_lmac_cmd *lmac_cmd, | ||
154 | u16 payload_size) | ||
155 | { | ||
156 | INIT_LIST_HEAD(&cmd->pending); | ||
157 | |||
158 | spin_lock(&iwm->cmd_lock); | ||
159 | |||
160 | cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm); | ||
161 | umac_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
162 | |||
163 | if (umac_cmd->resp) | ||
164 | list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd); | ||
165 | |||
166 | spin_unlock(&iwm->cmd_lock); | ||
167 | |||
168 | cmd->buf.start = cmd->buf.payload; | ||
169 | cmd->buf.len = 0; | ||
170 | |||
171 | if (lmac_cmd) { | ||
172 | cmd->buf.start -= sizeof(struct iwm_lmac_hdr); | ||
173 | |||
174 | lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
175 | lmac_cmd->count = cpu_to_le16(payload_size); | ||
176 | |||
177 | memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd)); | ||
178 | |||
179 | umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr)); | ||
180 | } else | ||
181 | umac_cmd->count = 0; | ||
182 | |||
183 | umac_cmd->count = cpu_to_le16(payload_size + | ||
184 | le16_to_cpu(umac_cmd->count)); | ||
185 | udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) + | ||
186 | le16_to_cpu(umac_cmd->count)); | ||
187 | |||
188 | memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); | ||
189 | memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd)); | ||
190 | } | ||
191 | |||
192 | void iwm_cmd_flush(struct iwm_priv *iwm) | ||
193 | { | ||
194 | struct iwm_wifi_cmd *wcmd, *wnext; | ||
195 | struct iwm_nonwifi_cmd *nwcmd, *nwnext; | ||
196 | |||
197 | list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) { | ||
198 | list_del(&wcmd->pending); | ||
199 | kfree(wcmd); | ||
200 | } | ||
201 | |||
202 | list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd, | ||
203 | pending) { | ||
204 | list_del(&nwcmd->pending); | ||
205 | kfree(nwcmd); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num) | ||
210 | { | ||
211 | struct iwm_wifi_cmd *cmd; | ||
212 | |||
213 | list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending) | ||
214 | if (cmd->seq_num == seq_num) { | ||
215 | list_del(&cmd->pending); | ||
216 | return cmd; | ||
217 | } | ||
218 | |||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, | ||
223 | u8 seq_num, u8 cmd_opcode) | ||
224 | { | ||
225 | struct iwm_nonwifi_cmd *cmd; | ||
226 | |||
227 | list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) | ||
228 | if ((cmd->seq_num == seq_num) && | ||
229 | (cmd->udma_cmd.opcode == cmd_opcode) && | ||
230 | (cmd->resp_received)) { | ||
231 | list_del(&cmd->pending); | ||
232 | return cmd; | ||
233 | } | ||
234 | |||
235 | return NULL; | ||
236 | } | ||
237 | |||
238 | static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm, | ||
239 | struct iwm_udma_out_nonwifi_hdr *hdr, | ||
240 | struct iwm_udma_nonwifi_cmd *cmd) | ||
241 | { | ||
242 | memset(hdr, 0, sizeof(*hdr)); | ||
243 | |||
244 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode); | ||
245 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp); | ||
246 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1); | ||
247 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW, | ||
248 | cmd->handle_by_hw); | ||
249 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); | ||
250 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM, | ||
251 | le16_to_cpu(cmd->seq_num)); | ||
252 | |||
253 | hdr->addr = cmd->addr; | ||
254 | hdr->op1_sz = cmd->op1_sz; | ||
255 | hdr->op2 = cmd->op2; | ||
256 | } | ||
257 | |||
258 | static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm, | ||
259 | struct iwm_nonwifi_cmd *cmd) | ||
260 | { | ||
261 | struct iwm_udma_out_nonwifi_hdr *udma_hdr; | ||
262 | struct iwm_nonwifi_cmd_buff *buf; | ||
263 | struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd; | ||
264 | |||
265 | buf = &cmd->buf; | ||
266 | |||
267 | buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr); | ||
268 | buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr); | ||
269 | |||
270 | udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start); | ||
271 | |||
272 | iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd); | ||
273 | |||
274 | IWM_DBG_CMD(iwm, DBG, | ||
275 | "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, " | ||
276 | "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, " | ||
277 | "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp, | ||
278 | udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr, | ||
279 | udma_cmd->op1_sz, udma_cmd->op2); | ||
280 | |||
281 | trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr); | ||
282 | return iwm_bus_send_chunk(iwm, buf->start, buf->len); | ||
283 | } | ||
284 | |||
285 | void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop) | ||
286 | { | ||
287 | struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf; | ||
288 | |||
289 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop); | ||
290 | } | ||
291 | |||
292 | void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, | ||
293 | struct iwm_udma_out_wifi_hdr *hdr, | ||
294 | struct iwm_udma_wifi_cmd *cmd) | ||
295 | { | ||
296 | memset(hdr, 0, sizeof(*hdr)); | ||
297 | |||
298 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI); | ||
299 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop); | ||
300 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); | ||
301 | |||
302 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT, | ||
303 | le16_to_cpu(cmd->count)); | ||
304 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group); | ||
305 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid); | ||
306 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset); | ||
307 | } | ||
308 | |||
309 | void iwm_build_umac_hdr(struct iwm_priv *iwm, | ||
310 | struct iwm_umac_fw_cmd_hdr *hdr, | ||
311 | struct iwm_umac_cmd *cmd) | ||
312 | { | ||
313 | memset(hdr, 0, sizeof(*hdr)); | ||
314 | |||
315 | SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT, | ||
316 | le16_to_cpu(cmd->count)); | ||
317 | SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color); | ||
318 | SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp); | ||
319 | |||
320 | hdr->cmd.cmd = cmd->id; | ||
321 | hdr->cmd.seq_num = cmd->seq_num; | ||
322 | } | ||
323 | |||
324 | static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm, | ||
325 | struct iwm_wifi_cmd *cmd) | ||
326 | { | ||
327 | struct iwm_umac_wifi_out_hdr *umac_hdr; | ||
328 | struct iwm_wifi_cmd_buff *buf; | ||
329 | struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd; | ||
330 | struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd; | ||
331 | int ret; | ||
332 | |||
333 | buf = &cmd->buf; | ||
334 | |||
335 | buf->start -= sizeof(struct iwm_umac_wifi_out_hdr); | ||
336 | buf->len += sizeof(struct iwm_umac_wifi_out_hdr); | ||
337 | |||
338 | umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start); | ||
339 | |||
340 | iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd); | ||
341 | iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd); | ||
342 | |||
343 | IWM_DBG_CMD(iwm, DBG, | ||
344 | "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, " | ||
345 | "eop = 0x%x, count = 0x%x, credit_group = 0x%x, " | ||
346 | "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n", | ||
347 | UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id, | ||
348 | udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group, | ||
349 | udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num); | ||
350 | |||
351 | if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH) | ||
352 | IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n", | ||
353 | cmd->lmac_cmd.id); | ||
354 | |||
355 | ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len); | ||
356 | |||
357 | /* We keep sending UMAC reset regardless of the command credits. | ||
358 | * The UMAC is supposed to be reset anyway and the Tx credits are | ||
359 | * reinitialized afterwards. If we are lucky, the reset could | ||
360 | * still be done even though we have run out of credits for the | ||
361 | * command pool at this moment.*/ | ||
362 | if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) { | ||
363 | IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n", | ||
364 | umac_cmd->id); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | trace_iwm_tx_wifi_cmd(iwm, umac_hdr); | ||
369 | return iwm_bus_send_chunk(iwm, buf->start, buf->len); | ||
370 | } | ||
371 | |||
372 | /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */ | ||
373 | int iwm_hal_send_target_cmd(struct iwm_priv *iwm, | ||
374 | struct iwm_udma_nonwifi_cmd *udma_cmd, | ||
375 | const void *payload) | ||
376 | { | ||
377 | struct iwm_nonwifi_cmd *cmd; | ||
378 | int ret, seq_num; | ||
379 | |||
380 | cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); | ||
381 | if (!cmd) { | ||
382 | IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n"); | ||
383 | return -ENOMEM; | ||
384 | } | ||
385 | |||
386 | seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); | ||
387 | |||
388 | if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || | ||
389 | cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { | ||
390 | cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz); | ||
391 | memcpy(&cmd->buf.payload, payload, cmd->buf.len); | ||
392 | } | ||
393 | |||
394 | ret = iwm_send_udma_nonwifi_cmd(iwm, cmd); | ||
395 | |||
396 | if (!udma_cmd->resp) | ||
397 | kfree(cmd); | ||
398 | |||
399 | if (ret < 0) | ||
400 | return ret; | ||
401 | |||
402 | return seq_num; | ||
403 | } | ||
404 | |||
405 | static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, | ||
406 | struct iwm_lmac_cmd *cmd) | ||
407 | { | ||
408 | memset(hdr, 0, sizeof(*hdr)); | ||
409 | |||
410 | hdr->id = cmd->id; | ||
411 | hdr->flags = 0; /* Is this ever used? */ | ||
412 | hdr->seq_num = cmd->seq_num; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. | ||
417 | * Sending command to the LMAC is equivalent to sending a | ||
418 | * regular UMAC command with the LMAC passthrough or the LMAC | ||
419 | * wrapper UMAC command IDs. | ||
420 | */ | ||
421 | int iwm_hal_send_host_cmd(struct iwm_priv *iwm, | ||
422 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
423 | struct iwm_umac_cmd *umac_cmd, | ||
424 | struct iwm_lmac_cmd *lmac_cmd, | ||
425 | const void *payload, u16 payload_size) | ||
426 | { | ||
427 | struct iwm_wifi_cmd *cmd; | ||
428 | struct iwm_lmac_hdr *hdr; | ||
429 | int lmac_hdr_len = 0; | ||
430 | int ret; | ||
431 | |||
432 | cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL); | ||
433 | if (!cmd) { | ||
434 | IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n"); | ||
435 | return -ENOMEM; | ||
436 | } | ||
437 | |||
438 | iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size); | ||
439 | |||
440 | if (lmac_cmd) { | ||
441 | hdr = (struct iwm_lmac_hdr *)(cmd->buf.start); | ||
442 | |||
443 | iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd); | ||
444 | lmac_hdr_len = sizeof(struct iwm_lmac_hdr); | ||
445 | } | ||
446 | |||
447 | memcpy(cmd->buf.payload, payload, payload_size); | ||
448 | cmd->buf.len = le16_to_cpu(umac_cmd->count); | ||
449 | |||
450 | ret = iwm_send_udma_wifi_cmd(iwm, cmd); | ||
451 | |||
452 | /* We free the cmd if we're not expecting any response */ | ||
453 | if (!umac_cmd->resp) | ||
454 | kfree(cmd); | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * iwm_hal_send_umac_cmd(): This is a special case for | ||
460 | * iwm_hal_send_host_cmd() to send direct UMAC cmd (without | ||
461 | * LMAC involved). | ||
462 | */ | ||
463 | int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, | ||
464 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
465 | struct iwm_umac_cmd *umac_cmd, | ||
466 | const void *payload, u16 payload_size) | ||
467 | { | ||
468 | return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL, | ||
469 | payload, payload_size); | ||
470 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h deleted file mode 100644 index c20936d9b6b7..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/hal.h +++ /dev/null | |||
@@ -1,237 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef _IWM_HAL_H_ | ||
40 | #define _IWM_HAL_H_ | ||
41 | |||
42 | #include "umac.h" | ||
43 | |||
44 | #define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED) | ||
45 | #define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED) | ||
46 | #define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED) | ||
47 | |||
48 | #define SET_VAL8(s, name, val) \ | ||
49 | do { \ | ||
50 | s = (s & ~(name##_SEED << name##_POS)) | \ | ||
51 | ((val & name##_SEED) << name##_POS); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define SET_VAL16(s, name, val) \ | ||
55 | do { \ | ||
56 | s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ | ||
57 | ((val & name##_SEED) << name##_POS)); \ | ||
58 | } while (0) | ||
59 | |||
60 | #define SET_VAL32(s, name, val) \ | ||
61 | do { \ | ||
62 | s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ | ||
63 | ((val & name##_SEED) << name##_POS)); \ | ||
64 | } while (0) | ||
65 | |||
66 | |||
67 | #define UDMA_UMAC_INIT { .eop = 1, \ | ||
68 | .credit_group = 0x4, \ | ||
69 | .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ | ||
70 | .lmac_offset = 0 } | ||
71 | #define UDMA_LMAC_INIT { .eop = 1, \ | ||
72 | .credit_group = 0x4, \ | ||
73 | .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ | ||
74 | .lmac_offset = 4 } | ||
75 | |||
76 | |||
77 | /* UDMA IN OP CODE -- cmd bits [3:0] */ | ||
78 | #define UDMA_HDI_IN_NW_CMD_OPCODE_POS 0 | ||
79 | #define UDMA_HDI_IN_NW_CMD_OPCODE_SEED 0xF | ||
80 | |||
81 | #define UDMA_IN_OPCODE_GENERAL_RESP 0x0 | ||
82 | #define UDMA_IN_OPCODE_READ_RESP 0x1 | ||
83 | #define UDMA_IN_OPCODE_WRITE_RESP 0x2 | ||
84 | #define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5 | ||
85 | #define UDMA_IN_OPCODE_PERS_READ_RESP 0x6 | ||
86 | #define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7 | ||
87 | #define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8 | ||
88 | #define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9 | ||
89 | #define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA | ||
90 | #define UDMA_IN_OPCODE_SW_MSG 0xB | ||
91 | #define UDMA_IN_OPCODE_WIFI 0xF | ||
92 | #define UDMA_IN_OPCODE_WIFI_LMAC 0x1F | ||
93 | #define UDMA_IN_OPCODE_WIFI_UMAC 0x2F | ||
94 | |||
95 | /* HW API: udma_hdi_nonwifi API (OUT and IN) */ | ||
96 | |||
97 | /* iwm_udma_nonwifi_cmd request response -- bits [9:9] */ | ||
98 | #define UDMA_HDI_OUT_NW_CMD_RESP_POS 9 | ||
99 | #define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1 | ||
100 | |||
101 | /* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */ | ||
102 | #define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11 | ||
103 | #define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1 | ||
104 | |||
105 | /* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */ | ||
106 | #define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12 | ||
107 | #define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF | ||
108 | |||
109 | /* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */ | ||
110 | #define UDMA_IN_NW_HW_SEQ_NUM_POS 12 | ||
111 | #define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF | ||
112 | |||
113 | /* UDMA IN Non-WIFI HW signature -- bits [16:31] */ | ||
114 | #define UDMA_IN_NW_HW_SIG_POS 16 | ||
115 | #define UDMA_IN_NW_HW_SIG_SEED 0xFFFF | ||
116 | |||
117 | /* fixed signature */ | ||
118 | #define UDMA_IN_NW_HW_SIG 0xCBBC | ||
119 | |||
120 | /* UDMA IN Non-WIFI HW block length -- bits [32:35] */ | ||
121 | #define UDMA_IN_NW_HW_LENGTH_SEED 0xF | ||
122 | #define UDMA_IN_NW_HW_LENGTH_POS 32 | ||
123 | |||
124 | /* End of HW API: udma_hdi_nonwifi API (OUT and IN) */ | ||
125 | |||
126 | #define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032 | ||
127 | #define IWM_MAX_WIFI_HEADERS_SIZE 32 | ||
128 | #define IWM_MAX_NONWIFI_HEADERS_SIZE 16 | ||
129 | #define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ | ||
130 | IWM_MAX_NONWIFI_HEADERS_SIZE) | ||
131 | #define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ | ||
132 | IWM_MAX_WIFI_HEADERS_SIZE) | ||
133 | |||
134 | #define IWM_HAL_CONCATENATE_BUF_SIZE (32 * 1024) | ||
135 | |||
136 | struct iwm_wifi_cmd_buff { | ||
137 | u16 len; | ||
138 | u8 *start; | ||
139 | u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE]; | ||
140 | u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE]; | ||
141 | }; | ||
142 | |||
143 | struct iwm_nonwifi_cmd_buff { | ||
144 | u16 len; | ||
145 | u8 *start; | ||
146 | u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE]; | ||
147 | u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE]; | ||
148 | }; | ||
149 | |||
150 | struct iwm_udma_nonwifi_cmd { | ||
151 | u8 opcode; | ||
152 | u8 eop; | ||
153 | u8 resp; | ||
154 | u8 handle_by_hw; | ||
155 | __le32 addr; | ||
156 | __le32 op1_sz; | ||
157 | __le32 op2; | ||
158 | __le16 seq_num; | ||
159 | }; | ||
160 | |||
161 | struct iwm_udma_wifi_cmd { | ||
162 | __le16 count; | ||
163 | u8 eop; | ||
164 | u8 credit_group; | ||
165 | u8 ra_tid; | ||
166 | u8 lmac_offset; | ||
167 | }; | ||
168 | |||
169 | struct iwm_umac_cmd { | ||
170 | u8 id; | ||
171 | __le16 count; | ||
172 | u8 resp; | ||
173 | __le16 seq_num; | ||
174 | u8 color; | ||
175 | }; | ||
176 | |||
177 | struct iwm_lmac_cmd { | ||
178 | u8 id; | ||
179 | __le16 count; | ||
180 | u8 resp; | ||
181 | __le16 seq_num; | ||
182 | }; | ||
183 | |||
184 | struct iwm_nonwifi_cmd { | ||
185 | u16 seq_num; | ||
186 | bool resp_received; | ||
187 | struct list_head pending; | ||
188 | struct iwm_udma_nonwifi_cmd udma_cmd; | ||
189 | struct iwm_umac_cmd umac_cmd; | ||
190 | struct iwm_lmac_cmd lmac_cmd; | ||
191 | struct iwm_nonwifi_cmd_buff buf; | ||
192 | u32 flags; | ||
193 | }; | ||
194 | |||
195 | struct iwm_wifi_cmd { | ||
196 | u16 seq_num; | ||
197 | struct list_head pending; | ||
198 | struct iwm_udma_wifi_cmd udma_cmd; | ||
199 | struct iwm_umac_cmd umac_cmd; | ||
200 | struct iwm_lmac_cmd lmac_cmd; | ||
201 | struct iwm_wifi_cmd_buff buf; | ||
202 | u32 flags; | ||
203 | }; | ||
204 | |||
205 | void iwm_cmd_flush(struct iwm_priv *iwm); | ||
206 | |||
207 | struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, | ||
208 | u16 seq_num); | ||
209 | struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, | ||
210 | u8 seq_num, u8 cmd_opcode); | ||
211 | |||
212 | |||
213 | int iwm_hal_send_target_cmd(struct iwm_priv *iwm, | ||
214 | struct iwm_udma_nonwifi_cmd *ucmd, | ||
215 | const void *payload); | ||
216 | |||
217 | int iwm_hal_send_host_cmd(struct iwm_priv *iwm, | ||
218 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
219 | struct iwm_umac_cmd *umac_cmd, | ||
220 | struct iwm_lmac_cmd *lmac_cmd, | ||
221 | const void *payload, u16 payload_size); | ||
222 | |||
223 | int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, | ||
224 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
225 | struct iwm_umac_cmd *umac_cmd, | ||
226 | const void *payload, u16 payload_size); | ||
227 | |||
228 | u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm); | ||
229 | |||
230 | void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop); | ||
231 | void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, | ||
232 | struct iwm_udma_out_wifi_hdr *hdr, | ||
233 | struct iwm_udma_wifi_cmd *cmd); | ||
234 | void iwm_build_umac_hdr(struct iwm_priv *iwm, | ||
235 | struct iwm_umac_fw_cmd_hdr *hdr, | ||
236 | struct iwm_umac_cmd *cmd); | ||
237 | #endif /* _IWM_HAL_H_ */ | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h deleted file mode 100644 index 51d7efa15ae6..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ /dev/null | |||
@@ -1,367 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_H__ | ||
40 | #define __IWM_H__ | ||
41 | |||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/wireless.h> | ||
44 | #include <net/cfg80211.h> | ||
45 | |||
46 | #include "debug.h" | ||
47 | #include "hal.h" | ||
48 | #include "umac.h" | ||
49 | #include "lmac.h" | ||
50 | #include "eeprom.h" | ||
51 | #include "trace.h" | ||
52 | |||
53 | #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" | ||
54 | #define IWM_AUTHOR "<ilw@linux.intel.com>" | ||
55 | |||
56 | #define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX | ||
57 | #define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA | ||
58 | #define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW | ||
59 | #define IWM_SRC_NUM 3 | ||
60 | |||
61 | #define IWM_POWER_INDEX_MIN 0 | ||
62 | #define IWM_POWER_INDEX_MAX 5 | ||
63 | #define IWM_POWER_INDEX_DEFAULT 3 | ||
64 | |||
65 | struct iwm_conf { | ||
66 | u32 sdio_ior_timeout; | ||
67 | unsigned long calib_map; | ||
68 | unsigned long expected_calib_map; | ||
69 | u8 ct_kill_entry; | ||
70 | u8 ct_kill_exit; | ||
71 | bool reset_on_fatal_err; | ||
72 | bool auto_connect; | ||
73 | bool wimax_not_present; | ||
74 | bool enable_qos; | ||
75 | u32 mode; | ||
76 | |||
77 | u32 power_index; | ||
78 | u32 frag_threshold; | ||
79 | u32 rts_threshold; | ||
80 | bool cts_to_self; | ||
81 | |||
82 | u32 assoc_timeout; | ||
83 | u32 roam_timeout; | ||
84 | u32 wireless_mode; | ||
85 | |||
86 | u8 ibss_band; | ||
87 | u8 ibss_channel; | ||
88 | |||
89 | u8 mac_addr[ETH_ALEN]; | ||
90 | }; | ||
91 | |||
92 | enum { | ||
93 | COEX_MODE_SA = 1, | ||
94 | COEX_MODE_XOR, | ||
95 | COEX_MODE_CM, | ||
96 | COEX_MODE_MAX, | ||
97 | }; | ||
98 | |||
99 | struct iwm_if_ops; | ||
100 | struct iwm_wifi_cmd; | ||
101 | |||
102 | struct pool_entry { | ||
103 | int id; /* group id */ | ||
104 | int sid; /* super group id */ | ||
105 | int min_pages; /* min capacity in pages */ | ||
106 | int max_pages; /* max capacity in pages */ | ||
107 | int alloc_pages; /* allocated # of pages. incresed by driver */ | ||
108 | int total_freed_pages; /* total freed # of pages. incresed by UMAC */ | ||
109 | }; | ||
110 | |||
111 | struct spool_entry { | ||
112 | int id; | ||
113 | int max_pages; | ||
114 | int alloc_pages; | ||
115 | }; | ||
116 | |||
117 | struct iwm_tx_credit { | ||
118 | spinlock_t lock; | ||
119 | int pool_nr; | ||
120 | unsigned long full_pools_map; /* bitmap for # of filled tx pools */ | ||
121 | struct pool_entry pools[IWM_MACS_OUT_GROUPS]; | ||
122 | struct spool_entry spools[IWM_MACS_OUT_SGROUPS]; | ||
123 | }; | ||
124 | |||
125 | struct iwm_notif { | ||
126 | struct list_head pending; | ||
127 | u32 cmd_id; | ||
128 | void *cmd; | ||
129 | u8 src; | ||
130 | void *buf; | ||
131 | unsigned long buf_size; | ||
132 | }; | ||
133 | |||
134 | struct iwm_tid_info { | ||
135 | __le16 last_seq_num; | ||
136 | bool stopped; | ||
137 | struct mutex mutex; | ||
138 | }; | ||
139 | |||
140 | struct iwm_sta_info { | ||
141 | u8 addr[ETH_ALEN]; | ||
142 | bool valid; | ||
143 | bool qos; | ||
144 | u8 color; | ||
145 | struct iwm_tid_info tid_info[IWM_UMAC_TID_NR]; | ||
146 | }; | ||
147 | |||
148 | struct iwm_tx_info { | ||
149 | u8 sta; | ||
150 | u8 color; | ||
151 | u8 tid; | ||
152 | }; | ||
153 | |||
154 | struct iwm_rx_info { | ||
155 | unsigned long rx_size; | ||
156 | unsigned long rx_buf_size; | ||
157 | }; | ||
158 | |||
159 | #define IWM_NUM_KEYS 4 | ||
160 | |||
161 | struct iwm_umac_key_hdr { | ||
162 | u8 mac[ETH_ALEN]; | ||
163 | u8 key_idx; | ||
164 | u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */ | ||
165 | } __packed; | ||
166 | |||
167 | struct iwm_key { | ||
168 | struct iwm_umac_key_hdr hdr; | ||
169 | u32 cipher; | ||
170 | u8 key[WLAN_MAX_KEY_LEN]; | ||
171 | u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; | ||
172 | int key_len; | ||
173 | int seq_len; | ||
174 | }; | ||
175 | |||
176 | #define IWM_RX_ID_HASH 0xff | ||
177 | #define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) | ||
178 | |||
179 | #define IWM_STA_TABLE_NUM 16 | ||
180 | #define IWM_TX_LIST_SIZE 64 | ||
181 | #define IWM_RX_LIST_SIZE 256 | ||
182 | |||
183 | #define IWM_SCAN_ID_MAX 0xff | ||
184 | |||
185 | #define IWM_STATUS_READY 0 | ||
186 | #define IWM_STATUS_SCANNING 1 | ||
187 | #define IWM_STATUS_SCAN_ABORTING 2 | ||
188 | #define IWM_STATUS_SME_CONNECTING 3 | ||
189 | #define IWM_STATUS_ASSOCIATED 4 | ||
190 | #define IWM_STATUS_RESETTING 5 | ||
191 | |||
192 | struct iwm_tx_queue { | ||
193 | int id; | ||
194 | struct sk_buff_head queue; | ||
195 | struct sk_buff_head stopped_queue; | ||
196 | spinlock_t lock; | ||
197 | struct workqueue_struct *wq; | ||
198 | struct work_struct worker; | ||
199 | u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; | ||
200 | int concat_count; | ||
201 | u8 *concat_ptr; | ||
202 | }; | ||
203 | |||
204 | /* Queues 0 ~ 3 for AC data, 5 for iPAN */ | ||
205 | #define IWM_TX_QUEUES 5 | ||
206 | #define IWM_TX_DATA_QUEUES 4 | ||
207 | #define IWM_TX_CMD_QUEUE 4 | ||
208 | |||
209 | struct iwm_bss_info { | ||
210 | struct list_head node; | ||
211 | struct cfg80211_bss *cfg_bss; | ||
212 | struct iwm_umac_notif_bss_info *bss; | ||
213 | }; | ||
214 | |||
215 | typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf, | ||
216 | unsigned long buf_size, struct iwm_wifi_cmd *cmd); | ||
217 | |||
218 | #define IWM_WATCHDOG_PERIOD (6 * HZ) | ||
219 | |||
220 | struct iwm_priv { | ||
221 | struct wireless_dev *wdev; | ||
222 | struct iwm_if_ops *bus_ops; | ||
223 | |||
224 | struct iwm_conf conf; | ||
225 | |||
226 | unsigned long status; | ||
227 | |||
228 | struct list_head pending_notif; | ||
229 | wait_queue_head_t notif_queue; | ||
230 | |||
231 | wait_queue_head_t nonwifi_queue; | ||
232 | |||
233 | unsigned long calib_done_map; | ||
234 | struct { | ||
235 | u8 *buf; | ||
236 | u32 size; | ||
237 | } calib_res[CALIBRATION_CMD_NUM]; | ||
238 | |||
239 | struct iwm_umac_profile *umac_profile; | ||
240 | bool umac_profile_active; | ||
241 | |||
242 | u8 bssid[ETH_ALEN]; | ||
243 | u8 channel; | ||
244 | u16 rate; | ||
245 | u32 txpower; | ||
246 | |||
247 | struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; | ||
248 | struct list_head bss_list; | ||
249 | |||
250 | void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX]) | ||
251 | (struct iwm_priv *priv, u8 *buf, unsigned long buf_size); | ||
252 | |||
253 | const iwm_handler *umac_handlers; | ||
254 | const iwm_handler *lmac_handlers; | ||
255 | DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM); | ||
256 | DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM); | ||
257 | DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM); | ||
258 | |||
259 | struct list_head wifi_pending_cmd; | ||
260 | struct list_head nonwifi_pending_cmd; | ||
261 | u16 wifi_seq_num; | ||
262 | u8 nonwifi_seq_num; | ||
263 | spinlock_t cmd_lock; | ||
264 | |||
265 | u32 core_enabled; | ||
266 | |||
267 | u8 scan_id; | ||
268 | struct cfg80211_scan_request *scan_request; | ||
269 | |||
270 | struct sk_buff_head rx_list; | ||
271 | struct list_head rx_tickets; | ||
272 | spinlock_t ticket_lock; | ||
273 | struct list_head rx_packets[IWM_RX_ID_HASH]; | ||
274 | spinlock_t packet_lock[IWM_RX_ID_HASH]; | ||
275 | struct workqueue_struct *rx_wq; | ||
276 | struct work_struct rx_worker; | ||
277 | |||
278 | struct iwm_tx_credit tx_credit; | ||
279 | struct iwm_tx_queue txq[IWM_TX_QUEUES]; | ||
280 | |||
281 | struct iwm_key keys[IWM_NUM_KEYS]; | ||
282 | s8 default_key; | ||
283 | |||
284 | DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); | ||
285 | wait_queue_head_t wifi_ntfy_queue; | ||
286 | |||
287 | wait_queue_head_t mlme_queue; | ||
288 | |||
289 | struct iw_statistics wstats; | ||
290 | struct delayed_work stats_request; | ||
291 | struct delayed_work disconnect; | ||
292 | struct delayed_work ct_kill_delay; | ||
293 | |||
294 | struct iwm_debugfs dbg; | ||
295 | |||
296 | u8 *eeprom; | ||
297 | struct timer_list watchdog; | ||
298 | struct work_struct reset_worker; | ||
299 | struct work_struct auth_retry_worker; | ||
300 | struct mutex mutex; | ||
301 | |||
302 | u8 *req_ie; | ||
303 | int req_ie_len; | ||
304 | u8 *resp_ie; | ||
305 | int resp_ie_len; | ||
306 | |||
307 | struct iwm_fw_error_hdr *last_fw_err; | ||
308 | char umac_version[8]; | ||
309 | char lmac_version[8]; | ||
310 | |||
311 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); | ||
312 | }; | ||
313 | |||
314 | static inline void *iwm_private(struct iwm_priv *iwm) | ||
315 | { | ||
316 | BUG_ON(!iwm); | ||
317 | return &iwm->private; | ||
318 | } | ||
319 | |||
320 | #define hw_to_iwm(h) (h->iwm) | ||
321 | #define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy)) | ||
322 | #define iwm_to_wiphy(i) (i->wdev->wiphy) | ||
323 | #define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w)) | ||
324 | #define iwm_to_wdev(i) (i->wdev) | ||
325 | #define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w)) | ||
326 | #define iwm_to_ndev(i) (i->wdev->netdev) | ||
327 | #define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr)) | ||
328 | #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) | ||
329 | #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) | ||
330 | |||
331 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, | ||
332 | struct iwm_if_ops *if_ops); | ||
333 | void iwm_if_free(struct iwm_priv *iwm); | ||
334 | int iwm_if_add(struct iwm_priv *iwm); | ||
335 | void iwm_if_remove(struct iwm_priv *iwm); | ||
336 | int iwm_mode_to_nl80211_iftype(int mode); | ||
337 | int iwm_priv_init(struct iwm_priv *iwm); | ||
338 | void iwm_priv_deinit(struct iwm_priv *iwm); | ||
339 | void iwm_reset(struct iwm_priv *iwm); | ||
340 | void iwm_resetting(struct iwm_priv *iwm); | ||
341 | void iwm_tx_credit_init_pools(struct iwm_priv *iwm, | ||
342 | struct iwm_umac_notif_alive *alive); | ||
343 | int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); | ||
344 | int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, | ||
345 | u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size); | ||
346 | int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout); | ||
347 | void iwm_init_default_profile(struct iwm_priv *iwm, | ||
348 | struct iwm_umac_profile *profile); | ||
349 | void iwm_link_on(struct iwm_priv *iwm); | ||
350 | void iwm_link_off(struct iwm_priv *iwm); | ||
351 | int iwm_up(struct iwm_priv *iwm); | ||
352 | int iwm_down(struct iwm_priv *iwm); | ||
353 | |||
354 | /* TX API */ | ||
355 | int iwm_tid_to_queue(u16 tid); | ||
356 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); | ||
357 | void iwm_tx_worker(struct work_struct *work); | ||
358 | int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | ||
359 | |||
360 | /* RX API */ | ||
361 | void iwm_rx_setup_handlers(struct iwm_priv *iwm); | ||
362 | int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size); | ||
363 | int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, | ||
364 | struct iwm_wifi_cmd *cmd); | ||
365 | void iwm_rx_free(struct iwm_priv *iwm); | ||
366 | |||
367 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h deleted file mode 100644 index 5ddcdf8c70c0..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ /dev/null | |||
@@ -1,484 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_LMAC_H__ | ||
40 | #define __IWM_LMAC_H__ | ||
41 | |||
42 | struct iwm_lmac_hdr { | ||
43 | u8 id; | ||
44 | u8 flags; | ||
45 | __le16 seq_num; | ||
46 | } __packed; | ||
47 | |||
48 | /* LMAC commands */ | ||
49 | #define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1 | ||
50 | |||
51 | struct iwm_lmac_cal_cfg_elt { | ||
52 | __le32 enable; /* 1 means LMAC needs to do something */ | ||
53 | __le32 start; /* 1 to start calibration, 0 to stop */ | ||
54 | __le32 send_res; /* 1 for sending back results */ | ||
55 | __le32 apply_res; /* 1 for applying calibration results to HW */ | ||
56 | __le32 reserved; | ||
57 | } __packed; | ||
58 | |||
59 | struct iwm_lmac_cal_cfg_status { | ||
60 | struct iwm_lmac_cal_cfg_elt init; | ||
61 | struct iwm_lmac_cal_cfg_elt periodic; | ||
62 | __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */ | ||
63 | } __packed; | ||
64 | |||
65 | struct iwm_lmac_cal_cfg_cmd { | ||
66 | struct iwm_lmac_cal_cfg_status ucode_cfg; | ||
67 | struct iwm_lmac_cal_cfg_status driver_cfg; | ||
68 | __le32 reserved; | ||
69 | } __packed; | ||
70 | |||
71 | struct iwm_lmac_cal_cfg_resp { | ||
72 | __le32 status; | ||
73 | } __packed; | ||
74 | |||
75 | #define IWM_CARD_STATE_SW_HW_ENABLED 0x00 | ||
76 | #define IWM_CARD_STATE_HW_DISABLED 0x01 | ||
77 | #define IWM_CARD_STATE_SW_DISABLED 0x02 | ||
78 | #define IWM_CARD_STATE_CTKILL_DISABLED 0x04 | ||
79 | #define IWM_CARD_STATE_IS_RXON 0x10 | ||
80 | |||
81 | struct iwm_lmac_card_state { | ||
82 | __le32 flags; | ||
83 | } __packed; | ||
84 | |||
85 | /** | ||
86 | * COEX_PRIORITY_TABLE_CMD | ||
87 | * | ||
88 | * Priority entry for each state | ||
89 | * Will keep two tables, for STA and WIPAN | ||
90 | */ | ||
91 | enum { | ||
92 | /* UN-ASSOCIATION PART */ | ||
93 | COEX_UNASSOC_IDLE = 0, | ||
94 | COEX_UNASSOC_MANUAL_SCAN, | ||
95 | COEX_UNASSOC_AUTO_SCAN, | ||
96 | |||
97 | /* CALIBRATION */ | ||
98 | COEX_CALIBRATION, | ||
99 | COEX_PERIODIC_CALIBRATION, | ||
100 | |||
101 | /* CONNECTION */ | ||
102 | COEX_CONNECTION_ESTAB, | ||
103 | |||
104 | /* ASSOCIATION PART */ | ||
105 | COEX_ASSOCIATED_IDLE, | ||
106 | COEX_ASSOC_MANUAL_SCAN, | ||
107 | COEX_ASSOC_AUTO_SCAN, | ||
108 | COEX_ASSOC_ACTIVE_LEVEL, | ||
109 | |||
110 | /* RF ON/OFF */ | ||
111 | COEX_RF_ON, | ||
112 | COEX_RF_OFF, | ||
113 | COEX_STAND_ALONE_DEBUG, | ||
114 | |||
115 | /* IPNN */ | ||
116 | COEX_IPAN_ASSOC_LEVEL, | ||
117 | |||
118 | /* RESERVED */ | ||
119 | COEX_RSRVD1, | ||
120 | COEX_RSRVD2, | ||
121 | |||
122 | COEX_EVENTS_NUM | ||
123 | }; | ||
124 | |||
125 | #define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1 | ||
126 | #define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2 | ||
127 | #define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4 | ||
128 | |||
129 | struct coex_event { | ||
130 | u8 req_prio; | ||
131 | u8 win_med_prio; | ||
132 | u8 reserved; | ||
133 | u8 flags; | ||
134 | } __packed; | ||
135 | |||
136 | #define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1 | ||
137 | #define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4 | ||
138 | #define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8 | ||
139 | #define COEX_FLAGS_COEX_ENABLE_MSK 0x80 | ||
140 | |||
141 | struct iwm_coex_prio_table_cmd { | ||
142 | u8 flags; | ||
143 | u8 reserved[3]; | ||
144 | struct coex_event sta_prio[COEX_EVENTS_NUM]; | ||
145 | } __packed; | ||
146 | |||
147 | /* Coexistence definitions | ||
148 | * | ||
149 | * Constants to fill in the Priorities' Tables | ||
150 | * RP - Requested Priority | ||
151 | * WP - Win Medium Priority: priority assigned when the contention has been won | ||
152 | * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and | ||
153 | * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | ||
154 | */ | ||
155 | |||
156 | #define COEX_UNASSOC_IDLE_FLAGS 0 | ||
157 | #define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
158 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
159 | #define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
160 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
161 | #define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
162 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
163 | #define COEX_PERIODIC_CALIBRATION_FLAGS 0 | ||
164 | /* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX | ||
165 | * disconnect from network. */ | ||
166 | #define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
167 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
168 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
169 | #define COEX_ASSOCIATED_IDLE_FLAGS 0 | ||
170 | #define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
171 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
172 | #define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
173 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
174 | #define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 | ||
175 | #define COEX_RF_ON_FLAGS 0 | ||
176 | #define COEX_RF_OFF_FLAGS 0 | ||
177 | #define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
178 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
179 | #define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
180 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
181 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
182 | #define COEX_RSRVD1_FLAGS 0 | ||
183 | #define COEX_RSRVD2_FLAGS 0 | ||
184 | /* XOR_RF_ON is the event wrapping all radio ownership. We need | ||
185 | * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */ | ||
186 | #define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
187 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
188 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
189 | |||
190 | /* CT kill config command */ | ||
191 | struct iwm_ct_kill_cfg_cmd { | ||
192 | u32 exit_threshold; | ||
193 | u32 reserved; | ||
194 | u32 entry_threshold; | ||
195 | } __packed; | ||
196 | |||
197 | |||
198 | /* LMAC OP CODES */ | ||
199 | #define REPLY_PAD 0x0 | ||
200 | #define REPLY_ALIVE 0x1 | ||
201 | #define REPLY_ERROR 0x2 | ||
202 | #define REPLY_ECHO 0x3 | ||
203 | #define REPLY_HALT 0x6 | ||
204 | |||
205 | /* RXON state commands */ | ||
206 | #define REPLY_RX_ON 0x10 | ||
207 | #define REPLY_RX_ON_ASSOC 0x11 | ||
208 | #define REPLY_RX_OFF 0x12 | ||
209 | #define REPLY_QOS_PARAM 0x13 | ||
210 | #define REPLY_RX_ON_TIMING 0x14 | ||
211 | #define REPLY_INTERNAL_QOS_PARAM 0x15 | ||
212 | #define REPLY_RX_INT_TIMEOUT_CNFG 0x16 | ||
213 | #define REPLY_NULL 0x17 | ||
214 | |||
215 | /* Multi-Station support */ | ||
216 | #define REPLY_ADD_STA 0x18 | ||
217 | #define REPLY_REMOVE_STA 0x19 | ||
218 | #define REPLY_RESET_ALL_STA 0x1a | ||
219 | |||
220 | /* RX, TX */ | ||
221 | #define REPLY_ALM_RX 0x1b | ||
222 | #define REPLY_TX 0x1c | ||
223 | #define REPLY_TXFIFO_FLUSH 0x1e | ||
224 | |||
225 | /* MISC commands */ | ||
226 | #define REPLY_MGMT_MCAST_KEY 0x1f | ||
227 | #define REPLY_WEPKEY 0x20 | ||
228 | #define REPLY_INIT_IV 0x21 | ||
229 | #define REPLY_WRITE_MIB 0x22 | ||
230 | #define REPLY_READ_MIB 0x23 | ||
231 | #define REPLY_RADIO_FE 0x24 | ||
232 | #define REPLY_TXFIFO_CFG 0x25 | ||
233 | #define REPLY_WRITE_READ 0x26 | ||
234 | #define REPLY_INSTALL_SEC_KEY 0x27 | ||
235 | |||
236 | |||
237 | #define REPLY_RATE_SCALE 0x47 | ||
238 | #define REPLY_LEDS_CMD 0x48 | ||
239 | #define REPLY_TX_LINK_QUALITY_CMD 0x4e | ||
240 | #define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f | ||
241 | #define REPLY_WRITE2REG_CMD 0x50 | ||
242 | |||
243 | /* winfi-wifi coexistence */ | ||
244 | #define COEX_PRIORITY_TABLE_CMD 0x5a | ||
245 | #define COEX_MEDIUM_NOTIFICATION 0x5b | ||
246 | #define COEX_EVENT_CMD 0x5c | ||
247 | |||
248 | /* more Protocol and Protocol-test commands */ | ||
249 | #define REPLY_MAX_SLEEP_TIME_CMD 0x61 | ||
250 | #define CALIBRATION_CFG_CMD 0x65 | ||
251 | #define CALIBRATION_RES_NOTIFICATION 0x66 | ||
252 | #define CALIBRATION_COMPLETE_NOTIFICATION 0x67 | ||
253 | |||
254 | /* Measurements */ | ||
255 | #define REPLY_QUIET_CMD 0x71 | ||
256 | #define REPLY_CHANNEL_SWITCH 0x72 | ||
257 | #define CHANNEL_SWITCH_NOTIFICATION 0x73 | ||
258 | |||
259 | #define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74 | ||
260 | #define SPECTRUM_MEASURE_NOTIFICATION 0x75 | ||
261 | #define REPLY_MEASUREMENT_ABORT_CMD 0x76 | ||
262 | |||
263 | /* Power Management */ | ||
264 | #define POWER_TABLE_CMD 0x77 | ||
265 | #define SAVE_RESTORE_ADDRESS_CMD 0x78 | ||
266 | #define REPLY_WATERMARK_CMD 0x79 | ||
267 | #define PM_DEBUG_STATISTIC_NOTIFIC 0x7B | ||
268 | #define PD_FLUSH_N_NOTIFICATION 0x7C | ||
269 | |||
270 | /* Scan commands and notifications */ | ||
271 | #define REPLY_SCAN_REQUEST_CMD 0x80 | ||
272 | #define REPLY_SCAN_ABORT_CMD 0x81 | ||
273 | #define SCAN_START_NOTIFICATION 0x82 | ||
274 | #define SCAN_RESULTS_NOTIFICATION 0x83 | ||
275 | #define SCAN_COMPLETE_NOTIFICATION 0x84 | ||
276 | |||
277 | /* Continuous TX commands */ | ||
278 | #define REPLY_CONT_TX_CMD 0x85 | ||
279 | #define END_OF_CONT_TX_NOTIFICATION 0x86 | ||
280 | |||
281 | /* Timer/Eeprom commands */ | ||
282 | #define TIMER_CMD 0x87 | ||
283 | #define EEPROM_WRITE_CMD 0x88 | ||
284 | |||
285 | /* PAPD commands */ | ||
286 | #define FEEDBACK_REQUEST_NOTIFICATION 0x8b | ||
287 | #define REPLY_CW_CMD 0x8c | ||
288 | |||
289 | /* IBSS/AP commands Continue */ | ||
290 | #define BEACON_NOTIFICATION 0x90 | ||
291 | #define REPLY_TX_BEACON 0x91 | ||
292 | #define REPLY_REQUEST_ATIM 0x93 | ||
293 | #define WHO_IS_AWAKE_NOTIFICATION 0x94 | ||
294 | #define TX_PWR_DBM_LIMIT_CMD 0x95 | ||
295 | #define QUIET_NOTIFICATION 0x96 | ||
296 | #define TX_PWR_TABLE_CMD 0x97 | ||
297 | #define TX_ANT_CONFIGURATION_CMD 0x98 | ||
298 | #define MEASURE_ABORT_NOTIFICATION 0x99 | ||
299 | #define REPLY_CALIBRATION_TUNE 0x9a | ||
300 | |||
301 | /* bt config command */ | ||
302 | #define REPLY_BT_CONFIG 0x9b | ||
303 | #define REPLY_STATISTICS_CMD 0x9c | ||
304 | #define STATISTICS_NOTIFICATION 0x9d | ||
305 | |||
306 | /* RF-KILL commands and notifications */ | ||
307 | #define REPLY_CARD_STATE_CMD 0xa0 | ||
308 | #define CARD_STATE_NOTIFICATION 0xa1 | ||
309 | |||
310 | /* Missed beacons notification */ | ||
311 | #define MISSED_BEACONS_NOTIFICATION 0xa2 | ||
312 | #define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3 | ||
313 | |||
314 | #define REPLY_CT_KILL_CONFIG_CMD 0xa4 | ||
315 | |||
316 | /* HD commands and notifications */ | ||
317 | #define REPLY_HD_PARAMS_CMD 0xa6 | ||
318 | #define HD_PARAMS_NOTIFICATION 0xa7 | ||
319 | #define SENSITIVITY_CMD 0xa8 | ||
320 | #define U_APSD_PARAMS_CMD 0xa9 | ||
321 | #define NOISY_PLATFORM_CMD 0xaa | ||
322 | #define ILLEGAL_CMD 0xac | ||
323 | #define REPLY_PHY_CALIBRATION_CMD 0xb0 | ||
324 | #define REPLAY_RX_GAIN_CALIB_CMD 0xb1 | ||
325 | |||
326 | /* WiPAN commands */ | ||
327 | #define REPLY_WIPAN_PARAMS_CMD 0xb2 | ||
328 | #define REPLY_WIPAN_RX_ON_CMD 0xb3 | ||
329 | #define REPLY_WIPAN_RX_ON_TIMING 0xb4 | ||
330 | #define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5 | ||
331 | #define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6 | ||
332 | #define REPLY_WIPAN_QOS_PARAM 0xb7 | ||
333 | #define WIPAN_REPLY_WEPKEY 0xb8 | ||
334 | |||
335 | /* BeamForming commands */ | ||
336 | #define BEAMFORMER_CFG_CMD 0xba | ||
337 | #define BEAMFORMEE_NOTIFICATION 0xbb | ||
338 | |||
339 | /* TGn new Commands */ | ||
340 | #define REPLY_RX_PHY_CMD 0xc0 | ||
341 | #define REPLY_RX_MPDU_CMD 0xc1 | ||
342 | #define REPLY_MULTICAST_HASH 0xc2 | ||
343 | #define REPLY_KDR_RX 0xc3 | ||
344 | #define REPLY_RX_DSP_EXT_INFO 0xc4 | ||
345 | #define REPLY_COMPRESSED_BA 0xc5 | ||
346 | |||
347 | /* PNC commands */ | ||
348 | #define PNC_CONFIG_CMD 0xc8 | ||
349 | #define PNC_UPDATE_TABLE_CMD 0xc9 | ||
350 | #define XVT_GENERAL_CTRL_CMD 0xca | ||
351 | #define REPLY_LEGACY_RADIO_FE 0xdd | ||
352 | |||
353 | /* WoWLAN commands */ | ||
354 | #define WOWLAN_PATTERNS 0xe0 | ||
355 | #define WOWLAN_WAKEUP_FILTER 0xe1 | ||
356 | #define WOWLAN_TSC_RSC_PARAM 0xe2 | ||
357 | #define WOWLAN_TKIP_PARAM 0xe3 | ||
358 | #define WOWLAN_KEK_KCK_MATERIAL 0xe4 | ||
359 | #define WOWLAN_GET_STATUSES 0xe5 | ||
360 | #define WOWLAN_TX_POWER_PER_DB 0xe6 | ||
361 | #define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES | ||
362 | |||
363 | #define REPLY_DEBUG_CMD 0xf0 | ||
364 | #define REPLY_DSP_DEBUG_CMD 0xf1 | ||
365 | #define REPLY_DEBUG_MONITOR_CMD 0xf2 | ||
366 | #define REPLY_DEBUG_XVT_CMD 0xf3 | ||
367 | #define REPLY_DEBUG_DC_CALIB 0xf4 | ||
368 | #define REPLY_DYNAMIC_BP 0xf5 | ||
369 | |||
370 | /* General purpose Commands */ | ||
371 | #define REPLY_GP1_CMD 0xfa | ||
372 | #define REPLY_GP2_CMD 0xfb | ||
373 | #define REPLY_GP3_CMD 0xfc | ||
374 | #define REPLY_GP4_CMD 0xfd | ||
375 | #define REPLY_REPLAY_WRAPPER 0xfe | ||
376 | #define REPLY_FRAME_DURATION_CALC_CMD 0xff | ||
377 | |||
378 | #define LMAC_COMMAND_ID_MAX 0xff | ||
379 | #define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1) | ||
380 | |||
381 | |||
382 | /* Calibration */ | ||
383 | |||
384 | enum { | ||
385 | PHY_CALIBRATE_DC_CMD = 0, | ||
386 | PHY_CALIBRATE_LO_CMD = 1, | ||
387 | PHY_CALIBRATE_RX_BB_CMD = 2, | ||
388 | PHY_CALIBRATE_TX_IQ_CMD = 3, | ||
389 | PHY_CALIBRATE_RX_IQ_CMD = 4, | ||
390 | PHY_CALIBRATION_NOISE_CMD = 5, | ||
391 | PHY_CALIBRATE_AGC_TABLE_CMD = 6, | ||
392 | PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7, | ||
393 | PHY_CALIBRATE_OPCODES_NUM, | ||
394 | SHILOH_PHY_CALIBRATE_DC_CMD = 8, | ||
395 | SHILOH_PHY_CALIBRATE_LO_CMD = 9, | ||
396 | SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10, | ||
397 | SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11, | ||
398 | SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12, | ||
399 | SHILOH_PHY_CALIBRATION_NOISE_CMD = 13, | ||
400 | SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14, | ||
401 | SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, | ||
402 | SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16, | ||
403 | SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17, | ||
404 | CALIBRATION_CMD_NUM, | ||
405 | }; | ||
406 | |||
407 | enum { | ||
408 | CALIB_CFG_RX_BB_IDX = 0, | ||
409 | CALIB_CFG_DC_IDX = 1, | ||
410 | CALIB_CFG_LO_IDX = 2, | ||
411 | CALIB_CFG_TX_IQ_IDX = 3, | ||
412 | CALIB_CFG_RX_IQ_IDX = 4, | ||
413 | CALIB_CFG_NOISE_IDX = 5, | ||
414 | CALIB_CFG_CRYSTAL_IDX = 6, | ||
415 | CALIB_CFG_TEMPERATURE_IDX = 7, | ||
416 | CALIB_CFG_PAPD_IDX = 8, | ||
417 | CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX, | ||
418 | CALIB_CFG_MODULE_NUM, | ||
419 | }; | ||
420 | |||
421 | #define IWM_CALIB_MAP_INIT_MSK 0xFFFF | ||
422 | #define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) | ||
423 | #define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) | ||
424 | #define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM) | ||
425 | |||
426 | struct iwm_lmac_calib_hdr { | ||
427 | u8 opcode; | ||
428 | u8 first_grp; | ||
429 | u8 grp_num; | ||
430 | u8 all_data_valid; | ||
431 | } __packed; | ||
432 | |||
433 | #define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7 | ||
434 | #define IWM_CALIB_FREQ_GROUPS_NR 5 | ||
435 | #define IWM_CALIB_DC_MODES_NR 12 | ||
436 | |||
437 | struct iwm_calib_rxiq_entry { | ||
438 | u16 ptam_postdist_ars; | ||
439 | u16 ptam_postdist_arc; | ||
440 | } __packed; | ||
441 | |||
442 | struct iwm_calib_rxiq_group { | ||
443 | struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR]; | ||
444 | } __packed; | ||
445 | |||
446 | struct iwm_lmac_calib_rxiq { | ||
447 | struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR]; | ||
448 | } __packed; | ||
449 | |||
450 | struct iwm_calib_rxiq { | ||
451 | struct iwm_lmac_calib_hdr hdr; | ||
452 | struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR]; | ||
453 | } __packed; | ||
454 | |||
455 | #define LMAC_STA_ID_SEED 0x0f | ||
456 | #define LMAC_STA_ID_POS 0 | ||
457 | |||
458 | #define LMAC_STA_COLOR_SEED 0x7 | ||
459 | #define LMAC_STA_COLOR_POS 4 | ||
460 | |||
461 | struct iwm_lmac_power_report { | ||
462 | u8 pa_status; | ||
463 | u8 pa_integ_res_A[3]; | ||
464 | u8 pa_integ_res_B[3]; | ||
465 | u8 pa_integ_res_C[3]; | ||
466 | } __packed; | ||
467 | |||
468 | struct iwm_lmac_tx_resp { | ||
469 | u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */ | ||
470 | u8 bt_kill_cnt; | ||
471 | __le16 retry_cnt; | ||
472 | __le32 initial_tx_rate; | ||
473 | __le16 wireless_media_time; | ||
474 | struct iwm_lmac_power_report power_report; | ||
475 | __le32 tfd_info; | ||
476 | __le16 seq_ctl; | ||
477 | __le16 byte_cnt; | ||
478 | u8 tlc_rate_info; | ||
479 | u8 ra_tid; | ||
480 | __le16 frame_ctl; | ||
481 | __le32 status; | ||
482 | } __packed; | ||
483 | |||
484 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c deleted file mode 100644 index 1f868b166d10..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ /dev/null | |||
@@ -1,847 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/sched.h> | ||
42 | #include <linux/ieee80211.h> | ||
43 | #include <linux/wireless.h> | ||
44 | #include <linux/slab.h> | ||
45 | #include <linux/moduleparam.h> | ||
46 | |||
47 | #include "iwm.h" | ||
48 | #include "debug.h" | ||
49 | #include "bus.h" | ||
50 | #include "umac.h" | ||
51 | #include "commands.h" | ||
52 | #include "hal.h" | ||
53 | #include "fw.h" | ||
54 | #include "rx.h" | ||
55 | |||
56 | static struct iwm_conf def_iwm_conf = { | ||
57 | |||
58 | .sdio_ior_timeout = 5000, | ||
59 | .calib_map = BIT(CALIB_CFG_DC_IDX) | | ||
60 | BIT(CALIB_CFG_LO_IDX) | | ||
61 | BIT(CALIB_CFG_TX_IQ_IDX) | | ||
62 | BIT(CALIB_CFG_RX_IQ_IDX) | | ||
63 | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), | ||
64 | .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | | ||
65 | BIT(PHY_CALIBRATE_LO_CMD) | | ||
66 | BIT(PHY_CALIBRATE_TX_IQ_CMD) | | ||
67 | BIT(PHY_CALIBRATE_RX_IQ_CMD) | | ||
68 | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), | ||
69 | .ct_kill_entry = 110, | ||
70 | .ct_kill_exit = 110, | ||
71 | .reset_on_fatal_err = 1, | ||
72 | .auto_connect = 1, | ||
73 | .enable_qos = 1, | ||
74 | .mode = UMAC_MODE_BSS, | ||
75 | |||
76 | /* UMAC configuration */ | ||
77 | .power_index = 0, | ||
78 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | ||
79 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | ||
80 | .cts_to_self = 0, | ||
81 | |||
82 | .assoc_timeout = 2, | ||
83 | .roam_timeout = 10, | ||
84 | .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | | ||
85 | WIRELESS_MODE_11N, | ||
86 | |||
87 | /* IBSS */ | ||
88 | .ibss_band = UMAC_BAND_2GHZ, | ||
89 | .ibss_channel = 1, | ||
90 | |||
91 | .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, | ||
92 | }; | ||
93 | |||
94 | static bool modparam_reset; | ||
95 | module_param_named(reset, modparam_reset, bool, 0644); | ||
96 | MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); | ||
97 | |||
98 | static bool modparam_wimax_enable = true; | ||
99 | module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644); | ||
100 | MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])"); | ||
101 | |||
102 | int iwm_mode_to_nl80211_iftype(int mode) | ||
103 | { | ||
104 | switch (mode) { | ||
105 | case UMAC_MODE_BSS: | ||
106 | return NL80211_IFTYPE_STATION; | ||
107 | case UMAC_MODE_IBSS: | ||
108 | return NL80211_IFTYPE_ADHOC; | ||
109 | default: | ||
110 | return NL80211_IFTYPE_UNSPECIFIED; | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static void iwm_statistics_request(struct work_struct *work) | ||
117 | { | ||
118 | struct iwm_priv *iwm = | ||
119 | container_of(work, struct iwm_priv, stats_request.work); | ||
120 | |||
121 | iwm_send_umac_stats_req(iwm, 0); | ||
122 | } | ||
123 | |||
124 | static void iwm_disconnect_work(struct work_struct *work) | ||
125 | { | ||
126 | struct iwm_priv *iwm = | ||
127 | container_of(work, struct iwm_priv, disconnect.work); | ||
128 | |||
129 | if (iwm->umac_profile_active) | ||
130 | iwm_invalidate_mlme_profile(iwm); | ||
131 | |||
132 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
133 | iwm->umac_profile_active = false; | ||
134 | memset(iwm->bssid, 0, ETH_ALEN); | ||
135 | iwm->channel = 0; | ||
136 | |||
137 | iwm_link_off(iwm); | ||
138 | |||
139 | wake_up_interruptible(&iwm->mlme_queue); | ||
140 | |||
141 | cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); | ||
142 | } | ||
143 | |||
144 | static void iwm_ct_kill_work(struct work_struct *work) | ||
145 | { | ||
146 | struct iwm_priv *iwm = | ||
147 | container_of(work, struct iwm_priv, ct_kill_delay.work); | ||
148 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
149 | |||
150 | IWM_INFO(iwm, "CT kill delay timeout\n"); | ||
151 | |||
152 | wiphy_rfkill_set_hw_state(wiphy, false); | ||
153 | } | ||
154 | |||
155 | static int __iwm_up(struct iwm_priv *iwm); | ||
156 | static int __iwm_down(struct iwm_priv *iwm); | ||
157 | |||
158 | static void iwm_reset_worker(struct work_struct *work) | ||
159 | { | ||
160 | struct iwm_priv *iwm; | ||
161 | struct iwm_umac_profile *profile = NULL; | ||
162 | int uninitialized_var(ret), retry = 0; | ||
163 | |||
164 | iwm = container_of(work, struct iwm_priv, reset_worker); | ||
165 | |||
166 | /* | ||
167 | * XXX: The iwm->mutex is introduced purely for this reset work, | ||
168 | * because the other users for iwm_up and iwm_down are only netdev | ||
169 | * ndo_open and ndo_stop which are already protected by rtnl. | ||
170 | * Please remove iwm->mutex together if iwm_reset_worker() is not | ||
171 | * required in the future. | ||
172 | */ | ||
173 | if (!mutex_trylock(&iwm->mutex)) { | ||
174 | IWM_WARN(iwm, "We are in the middle of interface bringing " | ||
175 | "UP/DOWN. Skip driver resetting.\n"); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | if (iwm->umac_profile_active) { | ||
180 | profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); | ||
181 | if (profile) | ||
182 | memcpy(profile, iwm->umac_profile, sizeof(*profile)); | ||
183 | else | ||
184 | IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); | ||
185 | } | ||
186 | |||
187 | __iwm_down(iwm); | ||
188 | |||
189 | while (retry++ < 3) { | ||
190 | ret = __iwm_up(iwm); | ||
191 | if (!ret) | ||
192 | break; | ||
193 | |||
194 | schedule_timeout_uninterruptible(10 * HZ); | ||
195 | } | ||
196 | |||
197 | if (ret) { | ||
198 | IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); | ||
199 | |||
200 | kfree(profile); | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | if (profile) { | ||
205 | IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n"); | ||
206 | memcpy(iwm->umac_profile, profile, sizeof(*profile)); | ||
207 | iwm_send_mlme_profile(iwm); | ||
208 | kfree(profile); | ||
209 | } else | ||
210 | clear_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
211 | |||
212 | out: | ||
213 | mutex_unlock(&iwm->mutex); | ||
214 | } | ||
215 | |||
216 | static void iwm_auth_retry_worker(struct work_struct *work) | ||
217 | { | ||
218 | struct iwm_priv *iwm; | ||
219 | int i, ret; | ||
220 | |||
221 | iwm = container_of(work, struct iwm_priv, auth_retry_worker); | ||
222 | if (iwm->umac_profile_active) { | ||
223 | ret = iwm_invalidate_mlme_profile(iwm); | ||
224 | if (ret < 0) | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
229 | |||
230 | ret = iwm_send_mlme_profile(iwm); | ||
231 | if (ret < 0) | ||
232 | return; | ||
233 | |||
234 | for (i = 0; i < IWM_NUM_KEYS; i++) | ||
235 | if (iwm->keys[i].key_len) | ||
236 | iwm_set_key(iwm, 0, &iwm->keys[i]); | ||
237 | |||
238 | iwm_set_tx_key(iwm, iwm->default_key); | ||
239 | } | ||
240 | |||
241 | |||
242 | |||
243 | static void iwm_watchdog(unsigned long data) | ||
244 | { | ||
245 | struct iwm_priv *iwm = (struct iwm_priv *)data; | ||
246 | |||
247 | IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); | ||
248 | |||
249 | if (modparam_reset) | ||
250 | iwm_resetting(iwm); | ||
251 | } | ||
252 | |||
253 | int iwm_priv_init(struct iwm_priv *iwm) | ||
254 | { | ||
255 | int i, j; | ||
256 | char name[32]; | ||
257 | |||
258 | iwm->status = 0; | ||
259 | INIT_LIST_HEAD(&iwm->pending_notif); | ||
260 | init_waitqueue_head(&iwm->notif_queue); | ||
261 | init_waitqueue_head(&iwm->nonwifi_queue); | ||
262 | init_waitqueue_head(&iwm->wifi_ntfy_queue); | ||
263 | init_waitqueue_head(&iwm->mlme_queue); | ||
264 | memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); | ||
265 | spin_lock_init(&iwm->tx_credit.lock); | ||
266 | INIT_LIST_HEAD(&iwm->wifi_pending_cmd); | ||
267 | INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd); | ||
268 | iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE; | ||
269 | iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE; | ||
270 | spin_lock_init(&iwm->cmd_lock); | ||
271 | iwm->scan_id = 1; | ||
272 | INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); | ||
273 | INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); | ||
274 | INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); | ||
275 | INIT_WORK(&iwm->reset_worker, iwm_reset_worker); | ||
276 | INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker); | ||
277 | INIT_LIST_HEAD(&iwm->bss_list); | ||
278 | |||
279 | skb_queue_head_init(&iwm->rx_list); | ||
280 | INIT_LIST_HEAD(&iwm->rx_tickets); | ||
281 | spin_lock_init(&iwm->ticket_lock); | ||
282 | for (i = 0; i < IWM_RX_ID_HASH; i++) { | ||
283 | INIT_LIST_HEAD(&iwm->rx_packets[i]); | ||
284 | spin_lock_init(&iwm->packet_lock[i]); | ||
285 | } | ||
286 | |||
287 | INIT_WORK(&iwm->rx_worker, iwm_rx_worker); | ||
288 | |||
289 | iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx"); | ||
290 | if (!iwm->rx_wq) | ||
291 | return -EAGAIN; | ||
292 | |||
293 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
294 | INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker); | ||
295 | snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i); | ||
296 | iwm->txq[i].id = i; | ||
297 | iwm->txq[i].wq = create_singlethread_workqueue(name); | ||
298 | if (!iwm->txq[i].wq) | ||
299 | return -EAGAIN; | ||
300 | |||
301 | skb_queue_head_init(&iwm->txq[i].queue); | ||
302 | skb_queue_head_init(&iwm->txq[i].stopped_queue); | ||
303 | spin_lock_init(&iwm->txq[i].lock); | ||
304 | } | ||
305 | |||
306 | for (i = 0; i < IWM_NUM_KEYS; i++) | ||
307 | memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); | ||
308 | |||
309 | iwm->default_key = -1; | ||
310 | |||
311 | for (i = 0; i < IWM_STA_TABLE_NUM; i++) | ||
312 | for (j = 0; j < IWM_UMAC_TID_NR; j++) { | ||
313 | mutex_init(&iwm->sta_table[i].tid_info[j].mutex); | ||
314 | iwm->sta_table[i].tid_info[j].stopped = false; | ||
315 | } | ||
316 | |||
317 | init_timer(&iwm->watchdog); | ||
318 | iwm->watchdog.function = iwm_watchdog; | ||
319 | iwm->watchdog.data = (unsigned long)iwm; | ||
320 | mutex_init(&iwm->mutex); | ||
321 | |||
322 | iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr), | ||
323 | GFP_KERNEL); | ||
324 | if (iwm->last_fw_err == NULL) | ||
325 | return -ENOMEM; | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | void iwm_priv_deinit(struct iwm_priv *iwm) | ||
331 | { | ||
332 | int i; | ||
333 | |||
334 | for (i = 0; i < IWM_TX_QUEUES; i++) | ||
335 | destroy_workqueue(iwm->txq[i].wq); | ||
336 | |||
337 | destroy_workqueue(iwm->rx_wq); | ||
338 | kfree(iwm->last_fw_err); | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * We reset all the structures, and we reset the UMAC. | ||
343 | * After calling this routine, you're expected to reload | ||
344 | * the firmware. | ||
345 | */ | ||
346 | void iwm_reset(struct iwm_priv *iwm) | ||
347 | { | ||
348 | struct iwm_notif *notif, *next; | ||
349 | |||
350 | if (test_bit(IWM_STATUS_READY, &iwm->status)) | ||
351 | iwm_target_reset(iwm); | ||
352 | |||
353 | if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) { | ||
354 | iwm->status = 0; | ||
355 | set_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
356 | } else | ||
357 | iwm->status = 0; | ||
358 | iwm->scan_id = 1; | ||
359 | |||
360 | list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { | ||
361 | list_del(¬if->pending); | ||
362 | kfree(notif->buf); | ||
363 | kfree(notif); | ||
364 | } | ||
365 | |||
366 | iwm_cmd_flush(iwm); | ||
367 | |||
368 | flush_workqueue(iwm->rx_wq); | ||
369 | |||
370 | iwm_link_off(iwm); | ||
371 | } | ||
372 | |||
373 | void iwm_resetting(struct iwm_priv *iwm) | ||
374 | { | ||
375 | set_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
376 | |||
377 | schedule_work(&iwm->reset_worker); | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Notification code: | ||
382 | * | ||
383 | * We're faced with the following issue: Any host command can | ||
384 | * have an answer or not, and if there's an answer to expect, | ||
385 | * it can be treated synchronously or asynchronously. | ||
386 | * To work around the synchronous answer case, we implemented | ||
387 | * our notification mechanism. | ||
388 | * When a code path needs to wait for a command response | ||
389 | * synchronously, it calls notif_handle(), which waits for the | ||
390 | * right notification to show up, and then process it. Before | ||
391 | * starting to wait, it registered as a waiter for this specific | ||
392 | * answer (by toggling a bit in on of the handler_map), so that | ||
393 | * the rx code knows that it needs to send a notification to the | ||
394 | * waiting processes. It does so by calling iwm_notif_send(), | ||
395 | * which adds the notification to the pending notifications list, | ||
396 | * and then wakes the waiting processes up. | ||
397 | */ | ||
398 | int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, | ||
399 | u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size) | ||
400 | { | ||
401 | struct iwm_notif *notif; | ||
402 | |||
403 | notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL); | ||
404 | if (!notif) { | ||
405 | IWM_ERR(iwm, "Couldn't alloc memory for notification\n"); | ||
406 | return -ENOMEM; | ||
407 | } | ||
408 | |||
409 | INIT_LIST_HEAD(¬if->pending); | ||
410 | notif->cmd = cmd; | ||
411 | notif->cmd_id = cmd_id; | ||
412 | notif->src = source; | ||
413 | notif->buf = kzalloc(buf_size, GFP_KERNEL); | ||
414 | if (!notif->buf) { | ||
415 | IWM_ERR(iwm, "Couldn't alloc notification buffer\n"); | ||
416 | kfree(notif); | ||
417 | return -ENOMEM; | ||
418 | } | ||
419 | notif->buf_size = buf_size; | ||
420 | memcpy(notif->buf, buf, buf_size); | ||
421 | list_add_tail(¬if->pending, &iwm->pending_notif); | ||
422 | |||
423 | wake_up_interruptible(&iwm->notif_queue); | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd, | ||
429 | u8 source) | ||
430 | { | ||
431 | struct iwm_notif *notif; | ||
432 | |||
433 | list_for_each_entry(notif, &iwm->pending_notif, pending) { | ||
434 | if ((notif->cmd_id == cmd) && (notif->src == source)) { | ||
435 | list_del(¬if->pending); | ||
436 | return notif; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | return NULL; | ||
441 | } | ||
442 | |||
443 | static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd, | ||
444 | u8 source, long timeout) | ||
445 | { | ||
446 | int ret; | ||
447 | struct iwm_notif *notif; | ||
448 | unsigned long *map = NULL; | ||
449 | |||
450 | switch (source) { | ||
451 | case IWM_SRC_LMAC: | ||
452 | map = &iwm->lmac_handler_map[0]; | ||
453 | break; | ||
454 | case IWM_SRC_UMAC: | ||
455 | map = &iwm->umac_handler_map[0]; | ||
456 | break; | ||
457 | case IWM_SRC_UDMA: | ||
458 | map = &iwm->udma_handler_map[0]; | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | set_bit(cmd, map); | ||
463 | |||
464 | ret = wait_event_interruptible_timeout(iwm->notif_queue, | ||
465 | ((notif = iwm_notif_find(iwm, cmd, source)) != NULL), | ||
466 | timeout); | ||
467 | clear_bit(cmd, map); | ||
468 | |||
469 | if (!ret) | ||
470 | return NULL; | ||
471 | |||
472 | return notif; | ||
473 | } | ||
474 | |||
475 | int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout) | ||
476 | { | ||
477 | int ret; | ||
478 | struct iwm_notif *notif; | ||
479 | |||
480 | notif = iwm_notif_wait(iwm, cmd, source, timeout); | ||
481 | if (!notif) | ||
482 | return -ETIME; | ||
483 | |||
484 | ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd); | ||
485 | kfree(notif->buf); | ||
486 | kfree(notif); | ||
487 | |||
488 | return ret; | ||
489 | } | ||
490 | |||
491 | static int iwm_config_boot_params(struct iwm_priv *iwm) | ||
492 | { | ||
493 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
494 | int ret; | ||
495 | |||
496 | /* check Wimax is off and config debug monitor */ | ||
497 | if (!modparam_wimax_enable) { | ||
498 | u32 data1 = 0x1f; | ||
499 | u32 addr1 = 0x606BE258; | ||
500 | |||
501 | u32 data2_set = 0x0; | ||
502 | u32 data2_clr = 0x1; | ||
503 | u32 addr2 = 0x606BE100; | ||
504 | |||
505 | u32 data3 = 0x1; | ||
506 | u32 addr3 = 0x606BEC00; | ||
507 | |||
508 | target_cmd.resp = 0; | ||
509 | target_cmd.handle_by_hw = 0; | ||
510 | target_cmd.eop = 1; | ||
511 | |||
512 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
513 | target_cmd.addr = cpu_to_le32(addr1); | ||
514 | target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); | ||
515 | target_cmd.op2 = 0; | ||
516 | |||
517 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); | ||
518 | if (ret < 0) { | ||
519 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE; | ||
524 | target_cmd.addr = cpu_to_le32(addr2); | ||
525 | target_cmd.op1_sz = cpu_to_le32(data2_set); | ||
526 | target_cmd.op2 = cpu_to_le32(data2_clr); | ||
527 | |||
528 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); | ||
529 | if (ret < 0) { | ||
530 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
535 | target_cmd.addr = cpu_to_le32(addr3); | ||
536 | target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); | ||
537 | target_cmd.op2 = 0; | ||
538 | |||
539 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3); | ||
540 | if (ret < 0) { | ||
541 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
542 | return ret; | ||
543 | } | ||
544 | } | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | void iwm_init_default_profile(struct iwm_priv *iwm, | ||
550 | struct iwm_umac_profile *profile) | ||
551 | { | ||
552 | memset(profile, 0, sizeof(struct iwm_umac_profile)); | ||
553 | |||
554 | profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; | ||
555 | profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; | ||
556 | profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE; | ||
557 | profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE; | ||
558 | |||
559 | if (iwm->conf.enable_qos) | ||
560 | profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED); | ||
561 | |||
562 | profile->wireless_mode = iwm->conf.wireless_mode; | ||
563 | profile->mode = cpu_to_le32(iwm->conf.mode); | ||
564 | |||
565 | profile->ibss.atim = 0; | ||
566 | profile->ibss.beacon_interval = 100; | ||
567 | profile->ibss.join_only = 0; | ||
568 | profile->ibss.band = iwm->conf.ibss_band; | ||
569 | profile->ibss.channel = iwm->conf.ibss_channel; | ||
570 | } | ||
571 | |||
572 | void iwm_link_on(struct iwm_priv *iwm) | ||
573 | { | ||
574 | netif_carrier_on(iwm_to_ndev(iwm)); | ||
575 | netif_tx_wake_all_queues(iwm_to_ndev(iwm)); | ||
576 | |||
577 | iwm_send_umac_stats_req(iwm, 0); | ||
578 | } | ||
579 | |||
580 | void iwm_link_off(struct iwm_priv *iwm) | ||
581 | { | ||
582 | struct iw_statistics *wstats = &iwm->wstats; | ||
583 | int i; | ||
584 | |||
585 | netif_tx_stop_all_queues(iwm_to_ndev(iwm)); | ||
586 | netif_carrier_off(iwm_to_ndev(iwm)); | ||
587 | |||
588 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
589 | skb_queue_purge(&iwm->txq[i].queue); | ||
590 | skb_queue_purge(&iwm->txq[i].stopped_queue); | ||
591 | |||
592 | iwm->txq[i].concat_count = 0; | ||
593 | iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; | ||
594 | |||
595 | flush_workqueue(iwm->txq[i].wq); | ||
596 | } | ||
597 | |||
598 | iwm_rx_free(iwm); | ||
599 | |||
600 | cancel_delayed_work_sync(&iwm->stats_request); | ||
601 | memset(wstats, 0, sizeof(struct iw_statistics)); | ||
602 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | ||
603 | |||
604 | kfree(iwm->req_ie); | ||
605 | iwm->req_ie = NULL; | ||
606 | iwm->req_ie_len = 0; | ||
607 | kfree(iwm->resp_ie); | ||
608 | iwm->resp_ie = NULL; | ||
609 | iwm->resp_ie_len = 0; | ||
610 | |||
611 | del_timer_sync(&iwm->watchdog); | ||
612 | } | ||
613 | |||
614 | static void iwm_bss_list_clean(struct iwm_priv *iwm) | ||
615 | { | ||
616 | struct iwm_bss_info *bss, *next; | ||
617 | |||
618 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { | ||
619 | list_del(&bss->node); | ||
620 | kfree(bss->bss); | ||
621 | kfree(bss); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static int iwm_channels_init(struct iwm_priv *iwm) | ||
626 | { | ||
627 | int ret; | ||
628 | |||
629 | ret = iwm_send_umac_channel_list(iwm); | ||
630 | if (ret) { | ||
631 | IWM_ERR(iwm, "Send channel list failed\n"); | ||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST, | ||
636 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
637 | if (ret) { | ||
638 | IWM_ERR(iwm, "Didn't get a channel list notification\n"); | ||
639 | return ret; | ||
640 | } | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int __iwm_up(struct iwm_priv *iwm) | ||
646 | { | ||
647 | int ret; | ||
648 | struct iwm_notif *notif_reboot, *notif_ack = NULL; | ||
649 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
650 | u32 wireless_mode; | ||
651 | |||
652 | ret = iwm_bus_enable(iwm); | ||
653 | if (ret) { | ||
654 | IWM_ERR(iwm, "Couldn't enable function\n"); | ||
655 | return ret; | ||
656 | } | ||
657 | |||
658 | iwm_rx_setup_handlers(iwm); | ||
659 | |||
660 | /* Wait for initial BARKER_REBOOT from hardware */ | ||
661 | notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION, | ||
662 | IWM_SRC_UDMA, 2 * HZ); | ||
663 | if (!notif_reboot) { | ||
664 | IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n"); | ||
665 | goto err_disable; | ||
666 | } | ||
667 | |||
668 | /* We send the barker back */ | ||
669 | ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16); | ||
670 | if (ret) { | ||
671 | IWM_ERR(iwm, "REBOOT barker response failed\n"); | ||
672 | kfree(notif_reboot); | ||
673 | goto err_disable; | ||
674 | } | ||
675 | |||
676 | kfree(notif_reboot->buf); | ||
677 | kfree(notif_reboot); | ||
678 | |||
679 | /* Wait for ACK_BARKER from hardware */ | ||
680 | notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION, | ||
681 | IWM_SRC_UDMA, 2 * HZ); | ||
682 | if (!notif_ack) { | ||
683 | IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n"); | ||
684 | goto err_disable; | ||
685 | } | ||
686 | |||
687 | kfree(notif_ack->buf); | ||
688 | kfree(notif_ack); | ||
689 | |||
690 | /* We start to config static boot parameters */ | ||
691 | ret = iwm_config_boot_params(iwm); | ||
692 | if (ret) { | ||
693 | IWM_ERR(iwm, "Config boot parameters failed\n"); | ||
694 | goto err_disable; | ||
695 | } | ||
696 | |||
697 | ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr); | ||
698 | if (ret) { | ||
699 | IWM_ERR(iwm, "MAC reading failed\n"); | ||
700 | goto err_disable; | ||
701 | } | ||
702 | memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr, | ||
703 | ETH_ALEN); | ||
704 | |||
705 | /* We can load the FWs */ | ||
706 | ret = iwm_load_fw(iwm); | ||
707 | if (ret) { | ||
708 | IWM_ERR(iwm, "FW loading failed\n"); | ||
709 | goto err_disable; | ||
710 | } | ||
711 | |||
712 | ret = iwm_eeprom_fat_channels(iwm); | ||
713 | if (ret) { | ||
714 | IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n"); | ||
715 | goto err_fw; | ||
716 | } | ||
717 | |||
718 | /* | ||
719 | * Read our SKU capabilities. | ||
720 | * If it's valid, we AND the configured wireless mode with the | ||
721 | * device EEPROM value as the current profile wireless mode. | ||
722 | */ | ||
723 | wireless_mode = iwm_eeprom_wireless_mode(iwm); | ||
724 | if (wireless_mode) { | ||
725 | iwm->conf.wireless_mode &= wireless_mode; | ||
726 | if (iwm->umac_profile) | ||
727 | iwm->umac_profile->wireless_mode = | ||
728 | iwm->conf.wireless_mode; | ||
729 | } else | ||
730 | IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n", | ||
731 | *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP))); | ||
732 | |||
733 | snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", | ||
734 | iwm->lmac_version, iwm->umac_version); | ||
735 | |||
736 | /* We configure the UMAC and enable the wifi module */ | ||
737 | ret = iwm_send_umac_config(iwm, | ||
738 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | | ||
739 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) | | ||
740 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN)); | ||
741 | if (ret) { | ||
742 | IWM_ERR(iwm, "UMAC config failed\n"); | ||
743 | goto err_fw; | ||
744 | } | ||
745 | |||
746 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, | ||
747 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
748 | if (ret) { | ||
749 | IWM_ERR(iwm, "Didn't get a wifi core status notification\n"); | ||
750 | goto err_fw; | ||
751 | } | ||
752 | |||
753 | if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | | ||
754 | UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { | ||
755 | IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n", | ||
756 | iwm->core_enabled); | ||
757 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, | ||
758 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
759 | if (ret) { | ||
760 | IWM_ERR(iwm, "Didn't get a core status notification\n"); | ||
761 | goto err_fw; | ||
762 | } | ||
763 | |||
764 | if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | | ||
765 | UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { | ||
766 | IWM_ERR(iwm, "Not all cores enabled: 0x%x\n", | ||
767 | iwm->core_enabled); | ||
768 | goto err_fw; | ||
769 | } else { | ||
770 | IWM_INFO(iwm, "All cores enabled\n"); | ||
771 | } | ||
772 | } | ||
773 | |||
774 | ret = iwm_channels_init(iwm); | ||
775 | if (ret < 0) { | ||
776 | IWM_ERR(iwm, "Couldn't init channels\n"); | ||
777 | goto err_fw; | ||
778 | } | ||
779 | |||
780 | /* Set the READY bit to indicate interface is brought up successfully */ | ||
781 | set_bit(IWM_STATUS_READY, &iwm->status); | ||
782 | |||
783 | return 0; | ||
784 | |||
785 | err_fw: | ||
786 | iwm_eeprom_exit(iwm); | ||
787 | |||
788 | err_disable: | ||
789 | ret = iwm_bus_disable(iwm); | ||
790 | if (ret < 0) | ||
791 | IWM_ERR(iwm, "Couldn't disable function\n"); | ||
792 | |||
793 | return -EIO; | ||
794 | } | ||
795 | |||
796 | int iwm_up(struct iwm_priv *iwm) | ||
797 | { | ||
798 | int ret; | ||
799 | |||
800 | mutex_lock(&iwm->mutex); | ||
801 | ret = __iwm_up(iwm); | ||
802 | mutex_unlock(&iwm->mutex); | ||
803 | |||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | static int __iwm_down(struct iwm_priv *iwm) | ||
808 | { | ||
809 | int ret; | ||
810 | |||
811 | /* The interface is already down */ | ||
812 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
813 | return 0; | ||
814 | |||
815 | if (iwm->scan_request) { | ||
816 | cfg80211_scan_done(iwm->scan_request, true); | ||
817 | iwm->scan_request = NULL; | ||
818 | } | ||
819 | |||
820 | clear_bit(IWM_STATUS_READY, &iwm->status); | ||
821 | |||
822 | iwm_eeprom_exit(iwm); | ||
823 | iwm_bss_list_clean(iwm); | ||
824 | iwm_init_default_profile(iwm, iwm->umac_profile); | ||
825 | iwm->umac_profile_active = false; | ||
826 | iwm->default_key = -1; | ||
827 | iwm->core_enabled = 0; | ||
828 | |||
829 | ret = iwm_bus_disable(iwm); | ||
830 | if (ret < 0) { | ||
831 | IWM_ERR(iwm, "Couldn't disable function\n"); | ||
832 | return ret; | ||
833 | } | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | int iwm_down(struct iwm_priv *iwm) | ||
839 | { | ||
840 | int ret; | ||
841 | |||
842 | mutex_lock(&iwm->mutex); | ||
843 | ret = __iwm_down(iwm); | ||
844 | mutex_unlock(&iwm->mutex); | ||
845 | |||
846 | return ret; | ||
847 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c deleted file mode 100644 index 5091d77e02ce..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ /dev/null | |||
@@ -1,191 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This is the netdev related hooks for iwm. | ||
26 | * | ||
27 | * Some interesting code paths: | ||
28 | * | ||
29 | * iwm_open() (Called at netdev interface bringup time) | ||
30 | * -> iwm_up() (main.c) | ||
31 | * -> iwm_bus_enable() | ||
32 | * -> if_sdio_enable() (In case of an SDIO bus) | ||
33 | * -> sdio_enable_func() | ||
34 | * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) | ||
35 | * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) | ||
36 | * -> iwm_load_fw() (fw.c) | ||
37 | * -> iwm_load_umac() | ||
38 | * -> iwm_load_lmac() (Calibration LMAC) | ||
39 | * -> iwm_load_lmac() (Operational LMAC) | ||
40 | * -> iwm_send_umac_config() | ||
41 | * | ||
42 | * iwm_stop() (Called at netdev interface bringdown time) | ||
43 | * -> iwm_down() | ||
44 | * -> iwm_bus_disable() | ||
45 | * -> if_sdio_disable() (In case of an SDIO bus) | ||
46 | * -> sdio_disable_func() | ||
47 | */ | ||
48 | #include <linux/netdevice.h> | ||
49 | #include <linux/slab.h> | ||
50 | |||
51 | #include "iwm.h" | ||
52 | #include "commands.h" | ||
53 | #include "cfg80211.h" | ||
54 | #include "debug.h" | ||
55 | |||
56 | static int iwm_open(struct net_device *ndev) | ||
57 | { | ||
58 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
59 | |||
60 | return iwm_up(iwm); | ||
61 | } | ||
62 | |||
63 | static int iwm_stop(struct net_device *ndev) | ||
64 | { | ||
65 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
66 | |||
67 | return iwm_down(iwm); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * iwm AC to queue mapping | ||
72 | * | ||
73 | * AC_VO -> queue 3 | ||
74 | * AC_VI -> queue 2 | ||
75 | * AC_BE -> queue 1 | ||
76 | * AC_BK -> queue 0 | ||
77 | */ | ||
78 | static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | ||
79 | |||
80 | int iwm_tid_to_queue(u16 tid) | ||
81 | { | ||
82 | if (tid > IWM_UMAC_TID_NR - 2) | ||
83 | return -EINVAL; | ||
84 | |||
85 | return iwm_1d_to_queue[tid]; | ||
86 | } | ||
87 | |||
88 | static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
89 | { | ||
90 | skb->priority = cfg80211_classify8021d(skb); | ||
91 | |||
92 | return iwm_1d_to_queue[skb->priority]; | ||
93 | } | ||
94 | |||
95 | static const struct net_device_ops iwm_netdev_ops = { | ||
96 | .ndo_open = iwm_open, | ||
97 | .ndo_stop = iwm_stop, | ||
98 | .ndo_start_xmit = iwm_xmit_frame, | ||
99 | .ndo_select_queue = iwm_select_queue, | ||
100 | }; | ||
101 | |||
102 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, | ||
103 | struct iwm_if_ops *if_ops) | ||
104 | { | ||
105 | struct net_device *ndev; | ||
106 | struct wireless_dev *wdev; | ||
107 | struct iwm_priv *iwm; | ||
108 | int ret = 0; | ||
109 | |||
110 | wdev = iwm_wdev_alloc(sizeof_bus, dev); | ||
111 | if (IS_ERR(wdev)) | ||
112 | return wdev; | ||
113 | |||
114 | iwm = wdev_to_iwm(wdev); | ||
115 | iwm->bus_ops = if_ops; | ||
116 | iwm->wdev = wdev; | ||
117 | |||
118 | ret = iwm_priv_init(iwm); | ||
119 | if (ret) { | ||
120 | dev_err(dev, "failed to init iwm_priv\n"); | ||
121 | goto out_wdev; | ||
122 | } | ||
123 | |||
124 | wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); | ||
125 | |||
126 | ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); | ||
127 | if (!ndev) { | ||
128 | dev_err(dev, "no memory for network device instance\n"); | ||
129 | ret = -ENOMEM; | ||
130 | goto out_priv; | ||
131 | } | ||
132 | |||
133 | ndev->netdev_ops = &iwm_netdev_ops; | ||
134 | ndev->ieee80211_ptr = wdev; | ||
135 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | ||
136 | wdev->netdev = ndev; | ||
137 | |||
138 | iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), | ||
139 | GFP_KERNEL); | ||
140 | if (!iwm->umac_profile) { | ||
141 | dev_err(dev, "Couldn't alloc memory for profile\n"); | ||
142 | ret = -ENOMEM; | ||
143 | goto out_profile; | ||
144 | } | ||
145 | |||
146 | iwm_init_default_profile(iwm, iwm->umac_profile); | ||
147 | |||
148 | return iwm; | ||
149 | |||
150 | out_profile: | ||
151 | free_netdev(ndev); | ||
152 | |||
153 | out_priv: | ||
154 | iwm_priv_deinit(iwm); | ||
155 | |||
156 | out_wdev: | ||
157 | iwm_wdev_free(iwm); | ||
158 | return ERR_PTR(ret); | ||
159 | } | ||
160 | |||
161 | void iwm_if_free(struct iwm_priv *iwm) | ||
162 | { | ||
163 | if (!iwm_to_ndev(iwm)) | ||
164 | return; | ||
165 | |||
166 | cancel_delayed_work_sync(&iwm->ct_kill_delay); | ||
167 | free_netdev(iwm_to_ndev(iwm)); | ||
168 | iwm_priv_deinit(iwm); | ||
169 | kfree(iwm->umac_profile); | ||
170 | iwm->umac_profile = NULL; | ||
171 | iwm_wdev_free(iwm); | ||
172 | } | ||
173 | |||
174 | int iwm_if_add(struct iwm_priv *iwm) | ||
175 | { | ||
176 | struct net_device *ndev = iwm_to_ndev(iwm); | ||
177 | int ret; | ||
178 | |||
179 | ret = register_netdev(ndev); | ||
180 | if (ret < 0) { | ||
181 | dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret); | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | void iwm_if_remove(struct iwm_priv *iwm) | ||
189 | { | ||
190 | unregister_netdev(iwm_to_ndev(iwm)); | ||
191 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c deleted file mode 100644 index 7d708f4395f3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ /dev/null | |||
@@ -1,1701 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/sched.h> | ||
42 | #include <linux/etherdevice.h> | ||
43 | #include <linux/wireless.h> | ||
44 | #include <linux/ieee80211.h> | ||
45 | #include <linux/if_arp.h> | ||
46 | #include <linux/list.h> | ||
47 | #include <linux/slab.h> | ||
48 | #include <net/iw_handler.h> | ||
49 | |||
50 | #include "iwm.h" | ||
51 | #include "debug.h" | ||
52 | #include "hal.h" | ||
53 | #include "umac.h" | ||
54 | #include "lmac.h" | ||
55 | #include "commands.h" | ||
56 | #include "rx.h" | ||
57 | #include "cfg80211.h" | ||
58 | #include "eeprom.h" | ||
59 | |||
60 | static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) | ||
61 | { | ||
62 | if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || | ||
63 | (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) | ||
64 | return -EINVAL; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) | ||
70 | { | ||
71 | return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), | ||
72 | 16); | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * Notification handlers: | ||
77 | * | ||
78 | * For every possible notification we can receive from the | ||
79 | * target, we have a handler. | ||
80 | * When we get a target notification, and there is no one | ||
81 | * waiting for it, it's just processed through the rx code | ||
82 | * path: | ||
83 | * | ||
84 | * iwm_rx_handle() | ||
85 | * -> iwm_rx_handle_umac() | ||
86 | * -> iwm_rx_handle_wifi() | ||
87 | * -> iwm_rx_handle_resp() | ||
88 | * -> iwm_ntf_*() | ||
89 | * | ||
90 | * OR | ||
91 | * | ||
92 | * -> iwm_rx_handle_non_wifi() | ||
93 | * | ||
94 | * If there are processes waiting for this notification, then | ||
95 | * iwm_rx_handle_wifi() just wakes those processes up and they | ||
96 | * grab the pending notification. | ||
97 | */ | ||
98 | static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, | ||
99 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
100 | { | ||
101 | struct iwm_umac_notif_error *error; | ||
102 | struct iwm_fw_error_hdr *fw_err; | ||
103 | |||
104 | error = (struct iwm_umac_notif_error *)buf; | ||
105 | fw_err = &error->err; | ||
106 | |||
107 | memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); | ||
108 | |||
109 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", | ||
110 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); | ||
111 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); | ||
112 | IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); | ||
113 | IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); | ||
114 | IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); | ||
115 | IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); | ||
116 | IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); | ||
117 | IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); | ||
118 | IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); | ||
119 | IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); | ||
120 | IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); | ||
121 | IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); | ||
122 | IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); | ||
123 | IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); | ||
124 | |||
125 | iwm_resetting(iwm); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, | ||
131 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
132 | { | ||
133 | struct iwm_umac_notif_alive *alive_resp = | ||
134 | (struct iwm_umac_notif_alive *)(buf); | ||
135 | u16 status = le16_to_cpu(alive_resp->status); | ||
136 | |||
137 | if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { | ||
138 | IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); | ||
139 | return -EIO; | ||
140 | } | ||
141 | |||
142 | iwm_tx_credit_init_pools(iwm, alive_resp); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, | ||
148 | unsigned long buf_size, | ||
149 | struct iwm_wifi_cmd *cmd) | ||
150 | { | ||
151 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
152 | struct iwm_umac_notif_init_complete *init_complete = | ||
153 | (struct iwm_umac_notif_init_complete *)(buf); | ||
154 | u16 status = le16_to_cpu(init_complete->status); | ||
155 | bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); | ||
156 | |||
157 | if (blocked) | ||
158 | IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); | ||
159 | else | ||
160 | IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); | ||
161 | |||
162 | wiphy_rfkill_set_hw_state(wiphy, blocked); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, | ||
168 | unsigned long buf_size, | ||
169 | struct iwm_wifi_cmd *cmd) | ||
170 | { | ||
171 | int pool_nr, total_freed_pages; | ||
172 | unsigned long pool_map; | ||
173 | int i, id; | ||
174 | struct iwm_umac_notif_page_dealloc *dealloc = | ||
175 | (struct iwm_umac_notif_page_dealloc *)buf; | ||
176 | |||
177 | pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); | ||
178 | pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); | ||
179 | |||
180 | IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " | ||
181 | "update map 0x%lx\n", pool_nr, pool_map); | ||
182 | |||
183 | spin_lock(&iwm->tx_credit.lock); | ||
184 | |||
185 | for (i = 0; i < pool_nr; i++) { | ||
186 | id = GET_VAL32(dealloc->grp_info[i], | ||
187 | UMAC_DEALLOC_NTFY_GROUP_NUM); | ||
188 | if (test_bit(id, &pool_map)) { | ||
189 | total_freed_pages = GET_VAL32(dealloc->grp_info[i], | ||
190 | UMAC_DEALLOC_NTFY_PAGE_CNT); | ||
191 | iwm_tx_credit_inc(iwm, id, total_freed_pages); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | spin_unlock(&iwm->tx_credit.lock); | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, | ||
201 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
202 | { | ||
203 | IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, | ||
209 | unsigned long buf_size, | ||
210 | struct iwm_wifi_cmd *cmd) | ||
211 | { | ||
212 | IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, | ||
218 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
219 | { | ||
220 | struct iwm_lmac_tx_resp *tx_resp; | ||
221 | struct iwm_umac_wifi_in_hdr *hdr; | ||
222 | |||
223 | tx_resp = (struct iwm_lmac_tx_resp *) | ||
224 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
225 | hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
226 | |||
227 | IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); | ||
228 | |||
229 | IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", | ||
230 | le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); | ||
231 | IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); | ||
232 | IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", | ||
233 | le16_to_cpu(tx_resp->retry_cnt)); | ||
234 | IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); | ||
235 | IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", | ||
236 | le16_to_cpu(tx_resp->byte_cnt)); | ||
237 | IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | |||
243 | static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, | ||
244 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
245 | { | ||
246 | u8 opcode; | ||
247 | u8 *calib_buf; | ||
248 | struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) | ||
249 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
250 | |||
251 | opcode = hdr->opcode; | ||
252 | |||
253 | BUG_ON(opcode >= CALIBRATION_CMD_NUM || | ||
254 | opcode < PHY_CALIBRATE_OPCODES_NUM); | ||
255 | |||
256 | IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", | ||
257 | opcode); | ||
258 | |||
259 | buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); | ||
260 | calib_buf = iwm->calib_res[opcode].buf; | ||
261 | |||
262 | if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { | ||
263 | kfree(calib_buf); | ||
264 | calib_buf = kzalloc(buf_size, GFP_KERNEL); | ||
265 | if (!calib_buf) { | ||
266 | IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); | ||
267 | return -ENOMEM; | ||
268 | } | ||
269 | iwm->calib_res[opcode].buf = calib_buf; | ||
270 | iwm->calib_res[opcode].size = buf_size; | ||
271 | } | ||
272 | |||
273 | memcpy(calib_buf, hdr, buf_size); | ||
274 | set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, | ||
280 | unsigned long buf_size, | ||
281 | struct iwm_wifi_cmd *cmd) | ||
282 | { | ||
283 | IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, | ||
289 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
290 | { | ||
291 | struct iwm_lmac_cal_cfg_resp *cal_resp; | ||
292 | |||
293 | cal_resp = (struct iwm_lmac_cal_cfg_resp *) | ||
294 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
295 | |||
296 | IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", | ||
297 | le32_to_cpu(cal_resp->status)); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, | ||
303 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
304 | { | ||
305 | struct iwm_umac_notif_wifi_status *status = | ||
306 | (struct iwm_umac_notif_wifi_status *)buf; | ||
307 | |||
308 | iwm->core_enabled |= le16_to_cpu(status->status); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static struct iwm_rx_ticket_node * | ||
314 | iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) | ||
315 | { | ||
316 | struct iwm_rx_ticket_node *ticket_node; | ||
317 | |||
318 | ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); | ||
319 | if (!ticket_node) { | ||
320 | IWM_ERR(iwm, "Couldn't allocate ticket node\n"); | ||
321 | return ERR_PTR(-ENOMEM); | ||
322 | } | ||
323 | |||
324 | ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket), | ||
325 | GFP_KERNEL); | ||
326 | if (!ticket_node->ticket) { | ||
327 | IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); | ||
328 | kfree(ticket_node); | ||
329 | return ERR_PTR(-ENOMEM); | ||
330 | } | ||
331 | |||
332 | INIT_LIST_HEAD(&ticket_node->node); | ||
333 | |||
334 | return ticket_node; | ||
335 | } | ||
336 | |||
337 | static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) | ||
338 | { | ||
339 | kfree(ticket_node->ticket); | ||
340 | kfree(ticket_node); | ||
341 | } | ||
342 | |||
343 | static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) | ||
344 | { | ||
345 | u8 id_hash = IWM_RX_ID_GET_HASH(id); | ||
346 | struct iwm_rx_packet *packet; | ||
347 | |||
348 | spin_lock(&iwm->packet_lock[id_hash]); | ||
349 | list_for_each_entry(packet, &iwm->rx_packets[id_hash], node) | ||
350 | if (packet->id == id) { | ||
351 | list_del(&packet->node); | ||
352 | spin_unlock(&iwm->packet_lock[id_hash]); | ||
353 | return packet; | ||
354 | } | ||
355 | |||
356 | spin_unlock(&iwm->packet_lock[id_hash]); | ||
357 | return NULL; | ||
358 | } | ||
359 | |||
360 | static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, | ||
361 | u32 size, u16 id) | ||
362 | { | ||
363 | struct iwm_rx_packet *packet; | ||
364 | |||
365 | packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); | ||
366 | if (!packet) { | ||
367 | IWM_ERR(iwm, "Couldn't allocate packet\n"); | ||
368 | return ERR_PTR(-ENOMEM); | ||
369 | } | ||
370 | |||
371 | packet->skb = dev_alloc_skb(size); | ||
372 | if (!packet->skb) { | ||
373 | IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); | ||
374 | kfree(packet); | ||
375 | return ERR_PTR(-ENOMEM); | ||
376 | } | ||
377 | |||
378 | packet->pkt_size = size; | ||
379 | |||
380 | skb_put(packet->skb, size); | ||
381 | memcpy(packet->skb->data, buf, size); | ||
382 | INIT_LIST_HEAD(&packet->node); | ||
383 | packet->id = id; | ||
384 | |||
385 | return packet; | ||
386 | } | ||
387 | |||
388 | void iwm_rx_free(struct iwm_priv *iwm) | ||
389 | { | ||
390 | struct iwm_rx_ticket_node *ticket, *nt; | ||
391 | struct iwm_rx_packet *packet, *np; | ||
392 | int i; | ||
393 | |||
394 | spin_lock(&iwm->ticket_lock); | ||
395 | list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { | ||
396 | list_del(&ticket->node); | ||
397 | iwm_rx_ticket_node_free(ticket); | ||
398 | } | ||
399 | spin_unlock(&iwm->ticket_lock); | ||
400 | |||
401 | for (i = 0; i < IWM_RX_ID_HASH; i++) { | ||
402 | spin_lock(&iwm->packet_lock[i]); | ||
403 | list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], | ||
404 | node) { | ||
405 | list_del(&packet->node); | ||
406 | kfree_skb(packet->skb); | ||
407 | kfree(packet); | ||
408 | } | ||
409 | spin_unlock(&iwm->packet_lock[i]); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, | ||
414 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
415 | { | ||
416 | struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = | ||
417 | (struct iwm_umac_notif_rx_ticket *)buf; | ||
418 | struct iwm_rx_ticket *ticket = | ||
419 | (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; | ||
420 | int i, schedule_rx = 0; | ||
421 | |||
422 | for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { | ||
423 | struct iwm_rx_ticket_node *ticket_node; | ||
424 | |||
425 | switch (le16_to_cpu(ticket->action)) { | ||
426 | case IWM_RX_TICKET_RELEASE: | ||
427 | case IWM_RX_TICKET_DROP: | ||
428 | /* We can push the packet to the stack */ | ||
429 | ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); | ||
430 | if (IS_ERR(ticket_node)) | ||
431 | return PTR_ERR(ticket_node); | ||
432 | |||
433 | IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n", | ||
434 | __le16_to_cpu(ticket->action) == | ||
435 | IWM_RX_TICKET_RELEASE ? | ||
436 | "RELEASE" : "DROP", | ||
437 | ticket->id); | ||
438 | spin_lock(&iwm->ticket_lock); | ||
439 | list_add_tail(&ticket_node->node, &iwm->rx_tickets); | ||
440 | spin_unlock(&iwm->ticket_lock); | ||
441 | |||
442 | /* | ||
443 | * We received an Rx ticket, most likely there's | ||
444 | * a packet pending for it, it's not worth going | ||
445 | * through the packet hash list to double check. | ||
446 | * Let's just fire the rx worker.. | ||
447 | */ | ||
448 | schedule_rx = 1; | ||
449 | |||
450 | break; | ||
451 | |||
452 | default: | ||
453 | IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", | ||
454 | ticket->action); | ||
455 | } | ||
456 | |||
457 | ticket++; | ||
458 | } | ||
459 | |||
460 | if (schedule_rx) | ||
461 | queue_work(iwm->rx_wq, &iwm->rx_worker); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, | ||
467 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
468 | { | ||
469 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
470 | struct iwm_rx_packet *packet; | ||
471 | u16 id, buf_offset; | ||
472 | u32 packet_size; | ||
473 | u8 id_hash; | ||
474 | |||
475 | IWM_DBG_RX(iwm, DBG, "\n"); | ||
476 | |||
477 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
478 | id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); | ||
479 | buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); | ||
480 | packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); | ||
481 | |||
482 | IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", | ||
483 | wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); | ||
484 | IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); | ||
485 | IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); | ||
486 | |||
487 | packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); | ||
488 | if (IS_ERR(packet)) | ||
489 | return PTR_ERR(packet); | ||
490 | |||
491 | id_hash = IWM_RX_ID_GET_HASH(id); | ||
492 | spin_lock(&iwm->packet_lock[id_hash]); | ||
493 | list_add_tail(&packet->node, &iwm->rx_packets[id_hash]); | ||
494 | spin_unlock(&iwm->packet_lock[id_hash]); | ||
495 | |||
496 | /* We might (unlikely) have received the packet _after_ the ticket */ | ||
497 | queue_work(iwm->rx_wq, &iwm->rx_worker); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | /* MLME handlers */ | ||
503 | static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, | ||
504 | unsigned long buf_size, | ||
505 | struct iwm_wifi_cmd *cmd) | ||
506 | { | ||
507 | struct iwm_umac_notif_assoc_start *start; | ||
508 | |||
509 | start = (struct iwm_umac_notif_assoc_start *)buf; | ||
510 | |||
511 | IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", | ||
512 | start->bssid, le32_to_cpu(start->roam_reason)); | ||
513 | |||
514 | wake_up_interruptible(&iwm->mlme_queue); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm) | ||
520 | { | ||
521 | if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || | ||
522 | iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && | ||
523 | (iwm->umac_profile->sec.ucast_cipher == | ||
524 | iwm->umac_profile->sec.mcast_cipher) && | ||
525 | (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN)) | ||
526 | return 1; | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, | ||
532 | unsigned long buf_size, | ||
533 | struct iwm_wifi_cmd *cmd) | ||
534 | { | ||
535 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
536 | struct ieee80211_channel *chan; | ||
537 | struct iwm_umac_notif_assoc_complete *complete = | ||
538 | (struct iwm_umac_notif_assoc_complete *)buf; | ||
539 | |||
540 | IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", | ||
541 | complete->bssid, complete->status); | ||
542 | |||
543 | switch (le32_to_cpu(complete->status)) { | ||
544 | case UMAC_ASSOC_COMPLETE_SUCCESS: | ||
545 | chan = ieee80211_get_channel(wiphy, | ||
546 | ieee80211_channel_to_frequency(complete->channel, | ||
547 | complete->band == UMAC_BAND_2GHZ ? | ||
548 | IEEE80211_BAND_2GHZ : | ||
549 | IEEE80211_BAND_5GHZ)); | ||
550 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
551 | /* Associated to a unallowed channel, disassociate. */ | ||
552 | __iwm_invalidate_mlme_profile(iwm); | ||
553 | IWM_WARN(iwm, "Couldn't associate with %pM due to " | ||
554 | "channel %d is disabled. Check your local " | ||
555 | "regulatory setting.\n", | ||
556 | complete->bssid, complete->channel); | ||
557 | goto failure; | ||
558 | } | ||
559 | |||
560 | set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
561 | memcpy(iwm->bssid, complete->bssid, ETH_ALEN); | ||
562 | iwm->channel = complete->channel; | ||
563 | |||
564 | /* Internal roaming state, avoid notifying SME. */ | ||
565 | if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) | ||
566 | && iwm->conf.mode == UMAC_MODE_BSS) { | ||
567 | cancel_delayed_work(&iwm->disconnect); | ||
568 | cfg80211_roamed(iwm_to_ndev(iwm), NULL, | ||
569 | complete->bssid, | ||
570 | iwm->req_ie, iwm->req_ie_len, | ||
571 | iwm->resp_ie, iwm->resp_ie_len, | ||
572 | GFP_KERNEL); | ||
573 | break; | ||
574 | } | ||
575 | |||
576 | iwm_link_on(iwm); | ||
577 | |||
578 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
579 | goto ibss; | ||
580 | |||
581 | if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) | ||
582 | cfg80211_connect_result(iwm_to_ndev(iwm), | ||
583 | complete->bssid, | ||
584 | iwm->req_ie, iwm->req_ie_len, | ||
585 | iwm->resp_ie, iwm->resp_ie_len, | ||
586 | WLAN_STATUS_SUCCESS, | ||
587 | GFP_KERNEL); | ||
588 | else | ||
589 | cfg80211_roamed(iwm_to_ndev(iwm), NULL, | ||
590 | complete->bssid, | ||
591 | iwm->req_ie, iwm->req_ie_len, | ||
592 | iwm->resp_ie, iwm->resp_ie_len, | ||
593 | GFP_KERNEL); | ||
594 | break; | ||
595 | case UMAC_ASSOC_COMPLETE_FAILURE: | ||
596 | failure: | ||
597 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
598 | memset(iwm->bssid, 0, ETH_ALEN); | ||
599 | iwm->channel = 0; | ||
600 | |||
601 | /* Internal roaming state, avoid notifying SME. */ | ||
602 | if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) | ||
603 | && iwm->conf.mode == UMAC_MODE_BSS) { | ||
604 | cancel_delayed_work(&iwm->disconnect); | ||
605 | break; | ||
606 | } | ||
607 | |||
608 | iwm_link_off(iwm); | ||
609 | |||
610 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
611 | goto ibss; | ||
612 | |||
613 | if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) | ||
614 | if (!iwm_is_open_wep_profile(iwm)) { | ||
615 | cfg80211_connect_result(iwm_to_ndev(iwm), | ||
616 | complete->bssid, | ||
617 | NULL, 0, NULL, 0, | ||
618 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
619 | GFP_KERNEL); | ||
620 | } else { | ||
621 | /* Let's try shared WEP auth */ | ||
622 | IWM_ERR(iwm, "Trying WEP shared auth\n"); | ||
623 | schedule_work(&iwm->auth_retry_worker); | ||
624 | } | ||
625 | else | ||
626 | cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, | ||
627 | GFP_KERNEL); | ||
628 | break; | ||
629 | default: | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | clear_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
634 | return 0; | ||
635 | |||
636 | ibss: | ||
637 | cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); | ||
638 | clear_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, | ||
643 | unsigned long buf_size, | ||
644 | struct iwm_wifi_cmd *cmd) | ||
645 | { | ||
646 | struct iwm_umac_notif_profile_invalidate *invalid; | ||
647 | u32 reason; | ||
648 | |||
649 | invalid = (struct iwm_umac_notif_profile_invalidate *)buf; | ||
650 | reason = le32_to_cpu(invalid->reason); | ||
651 | |||
652 | IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); | ||
653 | |||
654 | if (reason != UMAC_PROFILE_INVALID_REQUEST && | ||
655 | test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) | ||
656 | cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, | ||
657 | 0, WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
658 | GFP_KERNEL); | ||
659 | |||
660 | clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); | ||
661 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
662 | |||
663 | iwm->umac_profile_active = false; | ||
664 | memset(iwm->bssid, 0, ETH_ALEN); | ||
665 | iwm->channel = 0; | ||
666 | |||
667 | iwm_link_off(iwm); | ||
668 | |||
669 | wake_up_interruptible(&iwm->mlme_queue); | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | #define IWM_DISCONNECT_INTERVAL (5 * HZ) | ||
675 | |||
676 | static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, | ||
677 | unsigned long buf_size, | ||
678 | struct iwm_wifi_cmd *cmd) | ||
679 | { | ||
680 | IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); | ||
681 | |||
682 | schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, | ||
688 | unsigned long buf_size, | ||
689 | struct iwm_wifi_cmd *cmd) | ||
690 | { | ||
691 | int ret; | ||
692 | struct iwm_umac_notif_scan_complete *scan_complete = | ||
693 | (struct iwm_umac_notif_scan_complete *)buf; | ||
694 | u32 result = le32_to_cpu(scan_complete->result); | ||
695 | |||
696 | IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", | ||
697 | le32_to_cpu(scan_complete->type), | ||
698 | le32_to_cpu(scan_complete->result), | ||
699 | scan_complete->seq_num); | ||
700 | |||
701 | if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { | ||
702 | IWM_ERR(iwm, "Scan complete while device not scanning\n"); | ||
703 | return -EIO; | ||
704 | } | ||
705 | if (!iwm->scan_request) | ||
706 | return 0; | ||
707 | |||
708 | ret = iwm_cfg80211_inform_bss(iwm); | ||
709 | |||
710 | cfg80211_scan_done(iwm->scan_request, | ||
711 | (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); | ||
712 | iwm->scan_request = NULL; | ||
713 | |||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, | ||
718 | unsigned long buf_size, | ||
719 | struct iwm_wifi_cmd *cmd) | ||
720 | { | ||
721 | struct iwm_umac_notif_sta_info *umac_sta = | ||
722 | (struct iwm_umac_notif_sta_info *)buf; | ||
723 | struct iwm_sta_info *sta; | ||
724 | int i; | ||
725 | |||
726 | switch (le32_to_cpu(umac_sta->opcode)) { | ||
727 | case UMAC_OPCODE_ADD_MODIFY: | ||
728 | sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; | ||
729 | |||
730 | IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " | ||
731 | "addr = %pM, qos = %d\n", | ||
732 | sta->valid ? "Modify" : "Add", | ||
733 | GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), | ||
734 | GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), | ||
735 | umac_sta->mac_addr, | ||
736 | umac_sta->flags & UMAC_STA_FLAG_QOS); | ||
737 | |||
738 | sta->valid = true; | ||
739 | sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; | ||
740 | sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); | ||
741 | memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); | ||
742 | break; | ||
743 | case UMAC_OPCODE_REMOVE: | ||
744 | IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " | ||
745 | "addr = %pM\n", | ||
746 | GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), | ||
747 | GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), | ||
748 | umac_sta->mac_addr); | ||
749 | |||
750 | sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; | ||
751 | |||
752 | if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) | ||
753 | sta->valid = false; | ||
754 | |||
755 | break; | ||
756 | case UMAC_OPCODE_CLEAR_ALL: | ||
757 | for (i = 0; i < IWM_STA_TABLE_NUM; i++) | ||
758 | iwm->sta_table[i].valid = false; | ||
759 | |||
760 | break; | ||
761 | default: | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf, | ||
769 | unsigned long buf_size, | ||
770 | struct iwm_wifi_cmd *cmd) | ||
771 | { | ||
772 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
773 | |||
774 | IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n"); | ||
775 | |||
776 | wiphy_rfkill_set_hw_state(wiphy, true); | ||
777 | |||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, | ||
782 | unsigned long buf_size, | ||
783 | struct iwm_wifi_cmd *cmd) | ||
784 | { | ||
785 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
786 | struct ieee80211_mgmt *mgmt; | ||
787 | struct iwm_umac_notif_bss_info *umac_bss = | ||
788 | (struct iwm_umac_notif_bss_info *)buf; | ||
789 | struct ieee80211_channel *channel; | ||
790 | struct ieee80211_supported_band *band; | ||
791 | struct iwm_bss_info *bss; | ||
792 | s32 signal; | ||
793 | int freq; | ||
794 | u16 frame_len = le16_to_cpu(umac_bss->frame_len); | ||
795 | size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; | ||
796 | |||
797 | mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); | ||
798 | |||
799 | IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); | ||
800 | IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); | ||
801 | IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", | ||
802 | le32_to_cpu(umac_bss->timestamp)); | ||
803 | IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", | ||
804 | le16_to_cpu(umac_bss->table_idx)); | ||
805 | IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); | ||
806 | IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); | ||
807 | IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); | ||
808 | IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); | ||
809 | |||
810 | list_for_each_entry(bss, &iwm->bss_list, node) | ||
811 | if (bss->bss->table_idx == umac_bss->table_idx) | ||
812 | break; | ||
813 | |||
814 | if (&bss->node != &iwm->bss_list) { | ||
815 | /* Remove the old BSS entry, we will add it back later. */ | ||
816 | list_del(&bss->node); | ||
817 | kfree(bss->bss); | ||
818 | } else { | ||
819 | /* New BSS entry */ | ||
820 | |||
821 | bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); | ||
822 | if (!bss) { | ||
823 | IWM_ERR(iwm, "Couldn't allocate bss_info\n"); | ||
824 | return -ENOMEM; | ||
825 | } | ||
826 | } | ||
827 | |||
828 | bss->bss = kzalloc(bss_len, GFP_KERNEL); | ||
829 | if (!bss->bss) { | ||
830 | kfree(bss); | ||
831 | IWM_ERR(iwm, "Couldn't allocate bss\n"); | ||
832 | return -ENOMEM; | ||
833 | } | ||
834 | |||
835 | INIT_LIST_HEAD(&bss->node); | ||
836 | memcpy(bss->bss, umac_bss, bss_len); | ||
837 | |||
838 | if (umac_bss->band == UMAC_BAND_2GHZ) | ||
839 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
840 | else if (umac_bss->band == UMAC_BAND_5GHZ) | ||
841 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
842 | else { | ||
843 | IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); | ||
844 | goto err; | ||
845 | } | ||
846 | |||
847 | freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band); | ||
848 | channel = ieee80211_get_channel(wiphy, freq); | ||
849 | signal = umac_bss->rssi * 100; | ||
850 | |||
851 | bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, | ||
852 | mgmt, frame_len, | ||
853 | signal, GFP_KERNEL); | ||
854 | if (!bss->cfg_bss) | ||
855 | goto err; | ||
856 | |||
857 | list_add_tail(&bss->node, &iwm->bss_list); | ||
858 | |||
859 | return 0; | ||
860 | err: | ||
861 | kfree(bss->bss); | ||
862 | kfree(bss); | ||
863 | |||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, | ||
868 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
869 | { | ||
870 | struct iwm_umac_notif_bss_removed *bss_rm = | ||
871 | (struct iwm_umac_notif_bss_removed *)buf; | ||
872 | struct iwm_bss_info *bss, *next; | ||
873 | u16 table_idx; | ||
874 | int i; | ||
875 | |||
876 | for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { | ||
877 | table_idx = le16_to_cpu(bss_rm->entries[i]) & | ||
878 | IWM_BSS_REMOVE_INDEX_MSK; | ||
879 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) | ||
880 | if (bss->bss->table_idx == cpu_to_le16(table_idx)) { | ||
881 | struct ieee80211_mgmt *mgmt; | ||
882 | |||
883 | mgmt = (struct ieee80211_mgmt *) | ||
884 | (bss->bss->frame_buf); | ||
885 | IWM_DBG_MLME(iwm, ERR, "BSS removed: %pM\n", | ||
886 | mgmt->bssid); | ||
887 | list_del(&bss->node); | ||
888 | kfree(bss->bss); | ||
889 | kfree(bss); | ||
890 | } | ||
891 | } | ||
892 | |||
893 | return 0; | ||
894 | } | ||
895 | |||
896 | static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, | ||
897 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
898 | { | ||
899 | struct iwm_umac_notif_mgt_frame *mgt_frame = | ||
900 | (struct iwm_umac_notif_mgt_frame *)buf; | ||
901 | struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; | ||
902 | |||
903 | IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, | ||
904 | le16_to_cpu(mgt_frame->len)); | ||
905 | |||
906 | if (ieee80211_is_assoc_req(mgt->frame_control)) { | ||
907 | iwm->req_ie_len = le16_to_cpu(mgt_frame->len) | ||
908 | - offsetof(struct ieee80211_mgmt, | ||
909 | u.assoc_req.variable); | ||
910 | kfree(iwm->req_ie); | ||
911 | iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, | ||
912 | iwm->req_ie_len, GFP_KERNEL); | ||
913 | } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { | ||
914 | iwm->req_ie_len = le16_to_cpu(mgt_frame->len) | ||
915 | - offsetof(struct ieee80211_mgmt, | ||
916 | u.reassoc_req.variable); | ||
917 | kfree(iwm->req_ie); | ||
918 | iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, | ||
919 | iwm->req_ie_len, GFP_KERNEL); | ||
920 | } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { | ||
921 | iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) | ||
922 | - offsetof(struct ieee80211_mgmt, | ||
923 | u.assoc_resp.variable); | ||
924 | kfree(iwm->resp_ie); | ||
925 | iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, | ||
926 | iwm->resp_ie_len, GFP_KERNEL); | ||
927 | } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { | ||
928 | iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) | ||
929 | - offsetof(struct ieee80211_mgmt, | ||
930 | u.reassoc_resp.variable); | ||
931 | kfree(iwm->resp_ie); | ||
932 | iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, | ||
933 | iwm->resp_ie_len, GFP_KERNEL); | ||
934 | } else { | ||
935 | IWM_ERR(iwm, "Unsupported management frame: 0x%x", | ||
936 | le16_to_cpu(mgt->frame_control)); | ||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, | ||
944 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
945 | { | ||
946 | struct iwm_umac_notif_wifi_if *notif = | ||
947 | (struct iwm_umac_notif_wifi_if *)buf; | ||
948 | |||
949 | switch (notif->status) { | ||
950 | case WIFI_IF_NTFY_ASSOC_START: | ||
951 | return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); | ||
952 | case WIFI_IF_NTFY_ASSOC_COMPLETE: | ||
953 | return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); | ||
954 | case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: | ||
955 | return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); | ||
956 | case WIFI_IF_NTFY_CONNECTION_TERMINATED: | ||
957 | return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); | ||
958 | case WIFI_IF_NTFY_SCAN_COMPLETE: | ||
959 | return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); | ||
960 | case WIFI_IF_NTFY_STA_TABLE_CHANGE: | ||
961 | return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); | ||
962 | case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: | ||
963 | IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); | ||
964 | break; | ||
965 | case WIFI_IF_NTFY_RADIO_PREEMPTION: | ||
966 | return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd); | ||
967 | case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: | ||
968 | return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); | ||
969 | case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: | ||
970 | return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); | ||
971 | break; | ||
972 | case WIFI_IF_NTFY_MGMT_FRAME: | ||
973 | return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); | ||
974 | case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: | ||
975 | case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: | ||
976 | case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: | ||
977 | case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: | ||
978 | case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: | ||
979 | case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: | ||
980 | case WIFI_DBG_IF_NTFY_CNCT_ATC_START: | ||
981 | case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: | ||
982 | case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: | ||
983 | case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: | ||
984 | IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", | ||
985 | notif->status); | ||
986 | break; | ||
987 | default: | ||
988 | IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); | ||
989 | break; | ||
990 | } | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | #define IWM_STATS_UPDATE_INTERVAL (2 * HZ) | ||
996 | |||
997 | static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, | ||
998 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
999 | { | ||
1000 | struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; | ||
1001 | struct iw_statistics *wstats = &iwm->wstats; | ||
1002 | u16 max_rate = 0; | ||
1003 | int i; | ||
1004 | |||
1005 | IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); | ||
1006 | |||
1007 | if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
1008 | for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { | ||
1009 | max_rate = max_t(u16, max_rate, | ||
1010 | max(le16_to_cpu(stats->tx_rate[i]), | ||
1011 | le16_to_cpu(stats->rx_rate[i]))); | ||
1012 | } | ||
1013 | /* UMAC passes rate info multiplies by 2 */ | ||
1014 | iwm->rate = max_rate >> 1; | ||
1015 | } | ||
1016 | iwm->txpower = le32_to_cpu(stats->tx_power); | ||
1017 | |||
1018 | wstats->status = 0; | ||
1019 | |||
1020 | wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); | ||
1021 | wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); | ||
1022 | wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); | ||
1023 | wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); | ||
1024 | |||
1025 | wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); | ||
1026 | |||
1027 | /* according to cfg80211 */ | ||
1028 | if (stats->rssi_dbm < -110) | ||
1029 | wstats->qual.qual = 0; | ||
1030 | else if (stats->rssi_dbm > -40) | ||
1031 | wstats->qual.qual = 70; | ||
1032 | else | ||
1033 | wstats->qual.qual = stats->rssi_dbm + 110; | ||
1034 | |||
1035 | wstats->qual.level = stats->rssi_dbm; | ||
1036 | wstats->qual.noise = stats->noise_dbm; | ||
1037 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
1038 | |||
1039 | schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); | ||
1040 | |||
1041 | mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); | ||
1042 | |||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, | ||
1047 | unsigned long buf_size, | ||
1048 | struct iwm_wifi_cmd *cmd) | ||
1049 | { | ||
1050 | struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = | ||
1051 | (struct iwm_umac_cmd_eeprom_proxy *) | ||
1052 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
1053 | struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; | ||
1054 | u32 hdr_offset = le32_to_cpu(hdr->offset); | ||
1055 | u32 hdr_len = le32_to_cpu(hdr->len); | ||
1056 | u32 hdr_type = le32_to_cpu(hdr->type); | ||
1057 | |||
1058 | IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", | ||
1059 | hdr_type, hdr_len, hdr_offset); | ||
1060 | |||
1061 | if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) | ||
1062 | return -EINVAL; | ||
1063 | |||
1064 | switch (hdr_type) { | ||
1065 | case IWM_UMAC_CMD_EEPROM_TYPE_READ: | ||
1066 | memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); | ||
1067 | break; | ||
1068 | case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: | ||
1069 | default: | ||
1070 | return -ENOTSUPP; | ||
1071 | } | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, | ||
1077 | unsigned long buf_size, | ||
1078 | struct iwm_wifi_cmd *cmd) | ||
1079 | { | ||
1080 | struct iwm_umac_cmd_get_channel_list *ch_list = | ||
1081 | (struct iwm_umac_cmd_get_channel_list *) | ||
1082 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
1083 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
1084 | struct ieee80211_supported_band *band; | ||
1085 | int i; | ||
1086 | |||
1087 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
1088 | |||
1089 | for (i = 0; i < band->n_channels; i++) { | ||
1090 | unsigned long ch_mask_0 = | ||
1091 | le32_to_cpu(ch_list->ch[0].channels_mask); | ||
1092 | unsigned long ch_mask_2 = | ||
1093 | le32_to_cpu(ch_list->ch[2].channels_mask); | ||
1094 | |||
1095 | if (!test_bit(i, &ch_mask_0)) | ||
1096 | band->channels[i].flags |= IEEE80211_CHAN_DISABLED; | ||
1097 | |||
1098 | if (!test_bit(i, &ch_mask_2)) | ||
1099 | band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; | ||
1100 | } | ||
1101 | |||
1102 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
1103 | |||
1104 | for (i = 0; i < min(band->n_channels, 32); i++) { | ||
1105 | unsigned long ch_mask_1 = | ||
1106 | le32_to_cpu(ch_list->ch[1].channels_mask); | ||
1107 | unsigned long ch_mask_3 = | ||
1108 | le32_to_cpu(ch_list->ch[3].channels_mask); | ||
1109 | |||
1110 | if (!test_bit(i, &ch_mask_1)) | ||
1111 | band->channels[i].flags |= IEEE80211_CHAN_DISABLED; | ||
1112 | |||
1113 | if (!test_bit(i, &ch_mask_3)) | ||
1114 | band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; | ||
1115 | } | ||
1116 | |||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, | ||
1121 | unsigned long buf_size, | ||
1122 | struct iwm_wifi_cmd *cmd) | ||
1123 | { | ||
1124 | struct iwm_umac_notif_stop_resume_tx *stp_res_tx = | ||
1125 | (struct iwm_umac_notif_stop_resume_tx *)buf; | ||
1126 | struct iwm_sta_info *sta_info; | ||
1127 | struct iwm_tid_info *tid_info; | ||
1128 | u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id); | ||
1129 | u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk); | ||
1130 | int bit, ret = 0; | ||
1131 | bool stop = false; | ||
1132 | |||
1133 | IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n" | ||
1134 | "\tflags: 0x%x\n" | ||
1135 | "\tSTA id: %d\n" | ||
1136 | "\tTID bitmask: 0x%x\n", | ||
1137 | stp_res_tx->flags, stp_res_tx->sta_id, | ||
1138 | stp_res_tx->stop_resume_tid_msk); | ||
1139 | |||
1140 | if (stp_res_tx->flags & UMAC_STOP_TX_FLAG) | ||
1141 | stop = true; | ||
1142 | |||
1143 | sta_info = &iwm->sta_table[sta_id]; | ||
1144 | if (!sta_info->valid) { | ||
1145 | IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n", | ||
1146 | sta_id, stp_res_tx->sta_id); | ||
1147 | return -EINVAL; | ||
1148 | } | ||
1149 | |||
1150 | for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) { | ||
1151 | tid_info = &sta_info->tid_info[bit]; | ||
1152 | |||
1153 | mutex_lock(&tid_info->mutex); | ||
1154 | tid_info->stopped = stop; | ||
1155 | mutex_unlock(&tid_info->mutex); | ||
1156 | |||
1157 | if (!stop) { | ||
1158 | struct iwm_tx_queue *txq; | ||
1159 | int queue = iwm_tid_to_queue(bit); | ||
1160 | |||
1161 | if (queue < 0) | ||
1162 | continue; | ||
1163 | |||
1164 | txq = &iwm->txq[queue]; | ||
1165 | /* | ||
1166 | * If we resume, we have to move our SKBs | ||
1167 | * back to the tx queue and queue some work. | ||
1168 | */ | ||
1169 | spin_lock_bh(&txq->lock); | ||
1170 | skb_queue_splice_init(&txq->queue, &txq->stopped_queue); | ||
1171 | spin_unlock_bh(&txq->lock); | ||
1172 | |||
1173 | queue_work(txq->wq, &txq->worker); | ||
1174 | } | ||
1175 | |||
1176 | } | ||
1177 | |||
1178 | /* We send an ACK only for the stop case */ | ||
1179 | if (stop) | ||
1180 | ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx); | ||
1181 | |||
1182 | return ret; | ||
1183 | } | ||
1184 | |||
1185 | static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, | ||
1186 | unsigned long buf_size, | ||
1187 | struct iwm_wifi_cmd *cmd) | ||
1188 | { | ||
1189 | struct iwm_umac_wifi_if *hdr; | ||
1190 | |||
1191 | if (cmd == NULL) { | ||
1192 | IWM_ERR(iwm, "Couldn't find expected wifi command\n"); | ||
1193 | return -EINVAL; | ||
1194 | } | ||
1195 | |||
1196 | hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload; | ||
1197 | |||
1198 | IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " | ||
1199 | "oid is 0x%x\n", hdr->oid); | ||
1200 | |||
1201 | set_bit(hdr->oid, &iwm->wifi_ntfy[0]); | ||
1202 | wake_up_interruptible(&iwm->wifi_ntfy_queue); | ||
1203 | |||
1204 | switch (hdr->oid) { | ||
1205 | case UMAC_WIFI_IF_CMD_SET_PROFILE: | ||
1206 | iwm->umac_profile_active = true; | ||
1207 | break; | ||
1208 | default: | ||
1209 | break; | ||
1210 | } | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | #define CT_KILL_DELAY (30 * HZ) | ||
1216 | static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, | ||
1217 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
1218 | { | ||
1219 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
1220 | struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) | ||
1221 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
1222 | u32 flags = le32_to_cpu(state->flags); | ||
1223 | |||
1224 | IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", | ||
1225 | flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", | ||
1226 | flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); | ||
1227 | |||
1228 | if (flags & IWM_CARD_STATE_CTKILL_DISABLED) { | ||
1229 | /* | ||
1230 | * We got a CTKILL event: We bring the interface down in | ||
1231 | * oder to cool the device down, and try to bring it up | ||
1232 | * 30 seconds later. If it's still too hot, we'll go through | ||
1233 | * this code path again. | ||
1234 | */ | ||
1235 | cancel_delayed_work_sync(&iwm->ct_kill_delay); | ||
1236 | schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY); | ||
1237 | } | ||
1238 | |||
1239 | wiphy_rfkill_set_hw_state(wiphy, flags & | ||
1240 | (IWM_CARD_STATE_HW_DISABLED | | ||
1241 | IWM_CARD_STATE_CTKILL_DISABLED)); | ||
1242 | |||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, | ||
1247 | unsigned long buf_size) | ||
1248 | { | ||
1249 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
1250 | struct iwm_wifi_cmd *cmd; | ||
1251 | u8 source, cmd_id; | ||
1252 | u16 seq_num; | ||
1253 | u32 count; | ||
1254 | |||
1255 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
1256 | cmd_id = wifi_hdr->sw_hdr.cmd.cmd; | ||
1257 | source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
1258 | if (source >= IWM_SRC_NUM) { | ||
1259 | IWM_CRIT(iwm, "invalid source %d\n", source); | ||
1260 | return -EINVAL; | ||
1261 | } | ||
1262 | |||
1263 | if (cmd_id == REPLY_RX_MPDU_CMD) | ||
1264 | trace_iwm_rx_packet(iwm, buf, buf_size); | ||
1265 | else if ((cmd_id == UMAC_NOTIFY_OPCODE_RX_TICKET) && | ||
1266 | (source == UMAC_HDI_IN_SOURCE_FW)) | ||
1267 | trace_iwm_rx_ticket(iwm, buf, buf_size); | ||
1268 | else | ||
1269 | trace_iwm_rx_wifi_cmd(iwm, wifi_hdr); | ||
1270 | |||
1271 | count = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT); | ||
1272 | count += sizeof(struct iwm_umac_wifi_in_hdr) - | ||
1273 | sizeof(struct iwm_dev_cmd_hdr); | ||
1274 | if (count > buf_size) { | ||
1275 | IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); | ||
1276 | return -EINVAL; | ||
1277 | } | ||
1278 | |||
1279 | seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); | ||
1280 | |||
1281 | IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", | ||
1282 | cmd_id, source, seq_num); | ||
1283 | |||
1284 | /* | ||
1285 | * If this is a response to a previously sent command, there must | ||
1286 | * be a pending command for this sequence number. | ||
1287 | */ | ||
1288 | cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); | ||
1289 | |||
1290 | /* Notify the caller only for sync commands. */ | ||
1291 | switch (source) { | ||
1292 | case UMAC_HDI_IN_SOURCE_FHRX: | ||
1293 | if (iwm->lmac_handlers[cmd_id] && | ||
1294 | test_bit(cmd_id, &iwm->lmac_handler_map[0])) | ||
1295 | return iwm_notif_send(iwm, cmd, cmd_id, source, | ||
1296 | buf, count); | ||
1297 | break; | ||
1298 | case UMAC_HDI_IN_SOURCE_FW: | ||
1299 | if (iwm->umac_handlers[cmd_id] && | ||
1300 | test_bit(cmd_id, &iwm->umac_handler_map[0])) | ||
1301 | return iwm_notif_send(iwm, cmd, cmd_id, source, | ||
1302 | buf, count); | ||
1303 | break; | ||
1304 | case UMAC_HDI_IN_SOURCE_UDMA: | ||
1305 | break; | ||
1306 | } | ||
1307 | |||
1308 | return iwm_rx_handle_resp(iwm, buf, count, cmd); | ||
1309 | } | ||
1310 | |||
1311 | int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, | ||
1312 | struct iwm_wifi_cmd *cmd) | ||
1313 | { | ||
1314 | u8 source, cmd_id; | ||
1315 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
1316 | int ret = 0; | ||
1317 | |||
1318 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
1319 | cmd_id = wifi_hdr->sw_hdr.cmd.cmd; | ||
1320 | |||
1321 | source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
1322 | |||
1323 | IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); | ||
1324 | |||
1325 | switch (source) { | ||
1326 | case UMAC_HDI_IN_SOURCE_FHRX: | ||
1327 | if (iwm->lmac_handlers[cmd_id]) | ||
1328 | ret = iwm->lmac_handlers[cmd_id] | ||
1329 | (iwm, buf, buf_size, cmd); | ||
1330 | break; | ||
1331 | case UMAC_HDI_IN_SOURCE_FW: | ||
1332 | if (iwm->umac_handlers[cmd_id]) | ||
1333 | ret = iwm->umac_handlers[cmd_id] | ||
1334 | (iwm, buf, buf_size, cmd); | ||
1335 | break; | ||
1336 | case UMAC_HDI_IN_SOURCE_UDMA: | ||
1337 | ret = -EINVAL; | ||
1338 | break; | ||
1339 | } | ||
1340 | |||
1341 | kfree(cmd); | ||
1342 | |||
1343 | return ret; | ||
1344 | } | ||
1345 | |||
1346 | static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, | ||
1347 | unsigned long buf_size) | ||
1348 | { | ||
1349 | u8 seq_num; | ||
1350 | struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; | ||
1351 | struct iwm_nonwifi_cmd *cmd; | ||
1352 | |||
1353 | trace_iwm_rx_nonwifi_cmd(iwm, buf, buf_size); | ||
1354 | seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); | ||
1355 | |||
1356 | /* | ||
1357 | * We received a non wifi answer. | ||
1358 | * Let's check if there's a pending command for it, and if so | ||
1359 | * replace the command payload with the buffer, and then wake the | ||
1360 | * callers up. | ||
1361 | * That means we only support synchronised non wifi command response | ||
1362 | * schemes. | ||
1363 | */ | ||
1364 | list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) | ||
1365 | if (cmd->seq_num == seq_num) { | ||
1366 | cmd->resp_received = true; | ||
1367 | cmd->buf.len = buf_size; | ||
1368 | memcpy(cmd->buf.hdr, buf, buf_size); | ||
1369 | wake_up_interruptible(&iwm->nonwifi_queue); | ||
1370 | } | ||
1371 | |||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1375 | static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, | ||
1376 | unsigned long buf_size) | ||
1377 | { | ||
1378 | int ret = 0; | ||
1379 | u8 op_code; | ||
1380 | unsigned long buf_offset = 0; | ||
1381 | struct iwm_udma_in_hdr *hdr; | ||
1382 | |||
1383 | /* | ||
1384 | * To allow for a more efficient bus usage, UMAC | ||
1385 | * messages are encapsulated into UDMA ones. This | ||
1386 | * way we can have several UMAC messages in one bus | ||
1387 | * transfer. | ||
1388 | * A UDMA frame size is always aligned on 16 bytes, | ||
1389 | * and a UDMA frame must not start with a UMAC_PAD_TERMINAL | ||
1390 | * word. This is how we parse a bus frame into several | ||
1391 | * UDMA ones. | ||
1392 | */ | ||
1393 | while (buf_offset < buf_size) { | ||
1394 | |||
1395 | hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); | ||
1396 | |||
1397 | if (iwm_rx_check_udma_hdr(hdr) < 0) { | ||
1398 | IWM_DBG_RX(iwm, DBG, "End of frame\n"); | ||
1399 | break; | ||
1400 | } | ||
1401 | |||
1402 | op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); | ||
1403 | |||
1404 | IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); | ||
1405 | |||
1406 | if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { | ||
1407 | ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, | ||
1408 | buf_size - buf_offset); | ||
1409 | } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { | ||
1410 | if (GET_VAL32(hdr->cmd, | ||
1411 | UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != | ||
1412 | UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { | ||
1413 | IWM_ERR(iwm, "Incorrect hw signature\n"); | ||
1414 | return -EINVAL; | ||
1415 | } | ||
1416 | ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, | ||
1417 | buf_size - buf_offset); | ||
1418 | } else { | ||
1419 | IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); | ||
1420 | ret |= -EINVAL; | ||
1421 | } | ||
1422 | |||
1423 | buf_offset += iwm_rx_resp_size(hdr); | ||
1424 | } | ||
1425 | |||
1426 | return ret; | ||
1427 | } | ||
1428 | |||
1429 | int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) | ||
1430 | { | ||
1431 | struct iwm_udma_in_hdr *hdr; | ||
1432 | |||
1433 | hdr = (struct iwm_udma_in_hdr *)buf; | ||
1434 | |||
1435 | switch (le32_to_cpu(hdr->cmd)) { | ||
1436 | case UMAC_REBOOT_BARKER: | ||
1437 | if (test_bit(IWM_STATUS_READY, &iwm->status)) { | ||
1438 | IWM_ERR(iwm, "Unexpected BARKER\n"); | ||
1439 | |||
1440 | schedule_work(&iwm->reset_worker); | ||
1441 | |||
1442 | return 0; | ||
1443 | } | ||
1444 | |||
1445 | return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, | ||
1446 | IWM_SRC_UDMA, buf, buf_size); | ||
1447 | case UMAC_ACK_BARKER: | ||
1448 | return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, | ||
1449 | IWM_SRC_UDMA, NULL, 0); | ||
1450 | default: | ||
1451 | IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); | ||
1452 | return iwm_rx_handle_umac(iwm, buf, buf_size); | ||
1453 | } | ||
1454 | |||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | static const iwm_handler iwm_umac_handlers[] = | ||
1459 | { | ||
1460 | [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, | ||
1461 | [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, | ||
1462 | [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, | ||
1463 | [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, | ||
1464 | [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, | ||
1465 | [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, | ||
1466 | [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, | ||
1467 | [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, | ||
1468 | [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, | ||
1469 | [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, | ||
1470 | [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, | ||
1471 | [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx, | ||
1472 | [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, | ||
1473 | [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, | ||
1474 | }; | ||
1475 | |||
1476 | static const iwm_handler iwm_lmac_handlers[] = | ||
1477 | { | ||
1478 | [REPLY_TX] = iwm_ntf_tx, | ||
1479 | [REPLY_ALIVE] = iwm_ntf_lmac_version, | ||
1480 | [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, | ||
1481 | [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, | ||
1482 | [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, | ||
1483 | [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, | ||
1484 | [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, | ||
1485 | }; | ||
1486 | |||
1487 | void iwm_rx_setup_handlers(struct iwm_priv *iwm) | ||
1488 | { | ||
1489 | iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; | ||
1490 | iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; | ||
1491 | } | ||
1492 | |||
1493 | static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) | ||
1494 | { | ||
1495 | struct ieee80211_hdr *hdr; | ||
1496 | unsigned int hdr_len; | ||
1497 | |||
1498 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1499 | |||
1500 | if (!ieee80211_has_protected(hdr->frame_control)) | ||
1501 | return; | ||
1502 | |||
1503 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
1504 | if (hdr_total_len <= hdr_len) | ||
1505 | return; | ||
1506 | |||
1507 | memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); | ||
1508 | skb_pull(skb, (hdr_total_len - hdr_len)); | ||
1509 | } | ||
1510 | |||
1511 | static void iwm_rx_adjust_packet(struct iwm_priv *iwm, | ||
1512 | struct iwm_rx_packet *packet, | ||
1513 | struct iwm_rx_ticket_node *ticket_node) | ||
1514 | { | ||
1515 | u32 payload_offset = 0, payload_len; | ||
1516 | struct iwm_rx_ticket *ticket = ticket_node->ticket; | ||
1517 | struct iwm_rx_mpdu_hdr *mpdu_hdr; | ||
1518 | struct ieee80211_hdr *hdr; | ||
1519 | |||
1520 | mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; | ||
1521 | payload_offset += sizeof(struct iwm_rx_mpdu_hdr); | ||
1522 | /* Padding is 0 or 2 bytes */ | ||
1523 | payload_len = le16_to_cpu(mpdu_hdr->len) + | ||
1524 | (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); | ||
1525 | payload_len -= ticket->tail_len; | ||
1526 | |||
1527 | IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " | ||
1528 | "ticket offset:%d ticket tail len:%d\n", | ||
1529 | payload_len, payload_offset, ticket->payload_offset, | ||
1530 | ticket->tail_len); | ||
1531 | |||
1532 | IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); | ||
1533 | |||
1534 | skb_pull(packet->skb, payload_offset); | ||
1535 | skb_trim(packet->skb, payload_len); | ||
1536 | |||
1537 | iwm_remove_iv(packet->skb, ticket->payload_offset); | ||
1538 | |||
1539 | hdr = (struct ieee80211_hdr *) packet->skb->data; | ||
1540 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
1541 | /* UMAC handed QOS_DATA frame with 2 padding bytes appended | ||
1542 | * to the qos_ctl field in IEEE 802.11 headers. */ | ||
1543 | memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, | ||
1544 | packet->skb->data, | ||
1545 | ieee80211_hdrlen(hdr->frame_control) - | ||
1546 | IEEE80211_QOS_CTL_LEN); | ||
1547 | hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, | ||
1548 | IEEE80211_QOS_CTL_LEN + 2); | ||
1549 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | ||
1550 | } | ||
1551 | |||
1552 | IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", | ||
1553 | packet->skb->data, packet->skb->len); | ||
1554 | } | ||
1555 | |||
1556 | static void classify8023(struct sk_buff *skb) | ||
1557 | { | ||
1558 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1559 | |||
1560 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
1561 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
1562 | /* frame has qos control */ | ||
1563 | skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; | ||
1564 | } else { | ||
1565 | skb->priority = 0; | ||
1566 | } | ||
1567 | } | ||
1568 | |||
1569 | static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) | ||
1570 | { | ||
1571 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
1572 | struct net_device *ndev = iwm_to_ndev(iwm); | ||
1573 | struct sk_buff_head list; | ||
1574 | struct sk_buff *frame; | ||
1575 | |||
1576 | IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); | ||
1577 | |||
1578 | __skb_queue_head_init(&list); | ||
1579 | ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0, | ||
1580 | true); | ||
1581 | |||
1582 | while ((frame = __skb_dequeue(&list))) { | ||
1583 | ndev->stats.rx_packets++; | ||
1584 | ndev->stats.rx_bytes += frame->len; | ||
1585 | |||
1586 | frame->protocol = eth_type_trans(frame, ndev); | ||
1587 | frame->ip_summed = CHECKSUM_NONE; | ||
1588 | memset(frame->cb, 0, sizeof(frame->cb)); | ||
1589 | |||
1590 | if (netif_rx_ni(frame) == NET_RX_DROP) { | ||
1591 | IWM_ERR(iwm, "Packet dropped\n"); | ||
1592 | ndev->stats.rx_dropped++; | ||
1593 | } | ||
1594 | } | ||
1595 | } | ||
1596 | |||
1597 | static void iwm_rx_process_packet(struct iwm_priv *iwm, | ||
1598 | struct iwm_rx_packet *packet, | ||
1599 | struct iwm_rx_ticket_node *ticket_node) | ||
1600 | { | ||
1601 | int ret; | ||
1602 | struct sk_buff *skb = packet->skb; | ||
1603 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
1604 | struct net_device *ndev = iwm_to_ndev(iwm); | ||
1605 | |||
1606 | IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); | ||
1607 | |||
1608 | switch (le16_to_cpu(ticket_node->ticket->action)) { | ||
1609 | case IWM_RX_TICKET_RELEASE: | ||
1610 | IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); | ||
1611 | |||
1612 | iwm_rx_adjust_packet(iwm, packet, ticket_node); | ||
1613 | skb->dev = iwm_to_ndev(iwm); | ||
1614 | classify8023(skb); | ||
1615 | |||
1616 | if (le16_to_cpu(ticket_node->ticket->flags) & | ||
1617 | IWM_RX_TICKET_AMSDU_MSK) { | ||
1618 | iwm_rx_process_amsdu(iwm, skb); | ||
1619 | break; | ||
1620 | } | ||
1621 | |||
1622 | ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); | ||
1623 | if (ret < 0) { | ||
1624 | IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " | ||
1625 | "%d\n", ret); | ||
1626 | kfree_skb(packet->skb); | ||
1627 | break; | ||
1628 | } | ||
1629 | |||
1630 | IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); | ||
1631 | |||
1632 | ndev->stats.rx_packets++; | ||
1633 | ndev->stats.rx_bytes += skb->len; | ||
1634 | |||
1635 | skb->protocol = eth_type_trans(skb, ndev); | ||
1636 | skb->ip_summed = CHECKSUM_NONE; | ||
1637 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1638 | |||
1639 | if (netif_rx_ni(skb) == NET_RX_DROP) { | ||
1640 | IWM_ERR(iwm, "Packet dropped\n"); | ||
1641 | ndev->stats.rx_dropped++; | ||
1642 | } | ||
1643 | break; | ||
1644 | case IWM_RX_TICKET_DROP: | ||
1645 | IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n", | ||
1646 | le16_to_cpu(ticket_node->ticket->flags)); | ||
1647 | kfree_skb(packet->skb); | ||
1648 | break; | ||
1649 | default: | ||
1650 | IWM_ERR(iwm, "Unknown ticket action: %d\n", | ||
1651 | le16_to_cpu(ticket_node->ticket->action)); | ||
1652 | kfree_skb(packet->skb); | ||
1653 | } | ||
1654 | |||
1655 | kfree(packet); | ||
1656 | iwm_rx_ticket_node_free(ticket_node); | ||
1657 | } | ||
1658 | |||
1659 | /* | ||
1660 | * Rx data processing: | ||
1661 | * | ||
1662 | * We're receiving Rx packet from the LMAC, and Rx ticket from | ||
1663 | * the UMAC. | ||
1664 | * To forward a target data packet upstream (i.e. to the | ||
1665 | * kernel network stack), we must have received an Rx ticket | ||
1666 | * that tells us we're allowed to release this packet (ticket | ||
1667 | * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, | ||
1668 | * among other things, where valid data actually starts in the Rx | ||
1669 | * packet. | ||
1670 | */ | ||
1671 | void iwm_rx_worker(struct work_struct *work) | ||
1672 | { | ||
1673 | struct iwm_priv *iwm; | ||
1674 | struct iwm_rx_ticket_node *ticket, *next; | ||
1675 | |||
1676 | iwm = container_of(work, struct iwm_priv, rx_worker); | ||
1677 | |||
1678 | /* | ||
1679 | * We go through the tickets list and if there is a pending | ||
1680 | * packet for it, we push it upstream. | ||
1681 | * We stop whenever a ticket is missing its packet, as we're | ||
1682 | * supposed to send the packets in order. | ||
1683 | */ | ||
1684 | spin_lock(&iwm->ticket_lock); | ||
1685 | list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { | ||
1686 | struct iwm_rx_packet *packet = | ||
1687 | iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); | ||
1688 | |||
1689 | if (!packet) { | ||
1690 | IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " | ||
1691 | "to be handled first\n", | ||
1692 | le16_to_cpu(ticket->ticket->id)); | ||
1693 | break; | ||
1694 | } | ||
1695 | |||
1696 | list_del(&ticket->node); | ||
1697 | iwm_rx_process_packet(iwm, packet, ticket); | ||
1698 | } | ||
1699 | spin_unlock(&iwm->ticket_lock); | ||
1700 | } | ||
1701 | |||
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h deleted file mode 100644 index da0db91cee59..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rx.h +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_RX_H__ | ||
40 | #define __IWM_RX_H__ | ||
41 | |||
42 | #include <linux/skbuff.h> | ||
43 | |||
44 | #include "umac.h" | ||
45 | |||
46 | struct iwm_rx_ticket_node { | ||
47 | struct list_head node; | ||
48 | struct iwm_rx_ticket *ticket; | ||
49 | }; | ||
50 | |||
51 | struct iwm_rx_packet { | ||
52 | struct list_head node; | ||
53 | u16 id; | ||
54 | struct sk_buff *skb; | ||
55 | unsigned long pkt_size; | ||
56 | }; | ||
57 | |||
58 | void iwm_rx_worker(struct work_struct *work); | ||
59 | |||
60 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c deleted file mode 100644 index 0042f204b07f..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ /dev/null | |||
@@ -1,509 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * This is the SDIO bus specific hooks for iwm. | ||
41 | * It also is the module's entry point. | ||
42 | * | ||
43 | * Interesting code paths: | ||
44 | * iwm_sdio_probe() (Called by an SDIO bus scan) | ||
45 | * -> iwm_if_alloc() (netdev.c) | ||
46 | * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy) | ||
47 | * -> wiphy_new() | ||
48 | * -> wiphy_register() | ||
49 | * -> alloc_netdev_mq() | ||
50 | * -> register_netdev() | ||
51 | * | ||
52 | * iwm_sdio_remove() | ||
53 | * -> iwm_if_free() (netdev.c) | ||
54 | * -> unregister_netdev() | ||
55 | * -> iwm_wdev_free() (cfg80211.c) | ||
56 | * -> wiphy_unregister() | ||
57 | * -> wiphy_free() | ||
58 | * | ||
59 | * iwm_sdio_isr() (called in process context from the SDIO core code) | ||
60 | * -> queue_work(.., isr_worker) | ||
61 | * -- [async] --> iwm_sdio_isr_worker() | ||
62 | * -> iwm_rx_handle() | ||
63 | */ | ||
64 | |||
65 | #include <linux/kernel.h> | ||
66 | #include <linux/module.h> | ||
67 | #include <linux/slab.h> | ||
68 | #include <linux/netdevice.h> | ||
69 | #include <linux/debugfs.h> | ||
70 | #include <linux/mmc/sdio_ids.h> | ||
71 | #include <linux/mmc/sdio.h> | ||
72 | #include <linux/mmc/sdio_func.h> | ||
73 | |||
74 | #include "iwm.h" | ||
75 | #include "debug.h" | ||
76 | #include "bus.h" | ||
77 | #include "sdio.h" | ||
78 | |||
79 | static void iwm_sdio_isr_worker(struct work_struct *work) | ||
80 | { | ||
81 | struct iwm_sdio_priv *hw; | ||
82 | struct iwm_priv *iwm; | ||
83 | struct iwm_rx_info *rx_info; | ||
84 | struct sk_buff *skb; | ||
85 | u8 *rx_buf; | ||
86 | unsigned long rx_size; | ||
87 | |||
88 | hw = container_of(work, struct iwm_sdio_priv, isr_worker); | ||
89 | iwm = hw_to_iwm(hw); | ||
90 | |||
91 | while (!skb_queue_empty(&iwm->rx_list)) { | ||
92 | skb = skb_dequeue(&iwm->rx_list); | ||
93 | rx_info = skb_to_rx_info(skb); | ||
94 | rx_size = rx_info->rx_size; | ||
95 | rx_buf = skb->data; | ||
96 | |||
97 | IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size); | ||
98 | if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0) | ||
99 | IWM_WARN(iwm, "RX error\n"); | ||
100 | |||
101 | kfree_skb(skb); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static void iwm_sdio_isr(struct sdio_func *func) | ||
106 | { | ||
107 | struct iwm_priv *iwm; | ||
108 | struct iwm_sdio_priv *hw; | ||
109 | struct iwm_rx_info *rx_info; | ||
110 | struct sk_buff *skb; | ||
111 | unsigned long buf_size, read_size; | ||
112 | int ret; | ||
113 | u8 val; | ||
114 | |||
115 | hw = sdio_get_drvdata(func); | ||
116 | iwm = hw_to_iwm(hw); | ||
117 | |||
118 | buf_size = hw->blk_size; | ||
119 | |||
120 | /* We're checking the status */ | ||
121 | val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); | ||
122 | if (val == 0 || ret < 0) { | ||
123 | IWM_ERR(iwm, "Wrong INTR_STATUS\n"); | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | /* See if we have free buffers */ | ||
128 | if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { | ||
129 | IWM_ERR(iwm, "No buffer for more Rx frames\n"); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | /* We first read the transaction size */ | ||
134 | read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); | ||
135 | read_size = read_size << 8; | ||
136 | |||
137 | if (ret < 0) { | ||
138 | IWM_ERR(iwm, "Couldn't read the xfer size\n"); | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | /* We need to clear the INT register */ | ||
143 | sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); | ||
144 | if (ret < 0) { | ||
145 | IWM_ERR(iwm, "Couldn't clear the INT register\n"); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | while (buf_size < read_size) | ||
150 | buf_size <<= 1; | ||
151 | |||
152 | skb = dev_alloc_skb(buf_size); | ||
153 | if (!skb) { | ||
154 | IWM_ERR(iwm, "Couldn't alloc RX skb\n"); | ||
155 | return; | ||
156 | } | ||
157 | rx_info = skb_to_rx_info(skb); | ||
158 | rx_info->rx_size = read_size; | ||
159 | rx_info->rx_buf_size = buf_size; | ||
160 | |||
161 | /* Now we can read the actual buffer */ | ||
162 | ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), | ||
163 | IWM_SDIO_DATA_ADDR, read_size); | ||
164 | |||
165 | /* The skb is put on a driver's specific Rx SKB list */ | ||
166 | skb_queue_tail(&iwm->rx_list, skb); | ||
167 | |||
168 | /* We can now schedule the actual worker */ | ||
169 | queue_work(hw->isr_wq, &hw->isr_worker); | ||
170 | } | ||
171 | |||
172 | static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw) | ||
173 | { | ||
174 | struct iwm_priv *iwm = hw_to_iwm(hw); | ||
175 | |||
176 | flush_workqueue(hw->isr_wq); | ||
177 | |||
178 | skb_queue_purge(&iwm->rx_list); | ||
179 | } | ||
180 | |||
181 | /* Bus ops */ | ||
182 | static int if_sdio_enable(struct iwm_priv *iwm) | ||
183 | { | ||
184 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
185 | int ret; | ||
186 | |||
187 | sdio_claim_host(hw->func); | ||
188 | |||
189 | ret = sdio_enable_func(hw->func); | ||
190 | if (ret) { | ||
191 | IWM_ERR(iwm, "Couldn't enable the device: is TOP driver " | ||
192 | "loaded and functional?\n"); | ||
193 | goto release_host; | ||
194 | } | ||
195 | |||
196 | iwm_reset(iwm); | ||
197 | |||
198 | ret = sdio_claim_irq(hw->func, iwm_sdio_isr); | ||
199 | if (ret) { | ||
200 | IWM_ERR(iwm, "Failed to claim irq: %d\n", ret); | ||
201 | goto release_host; | ||
202 | } | ||
203 | |||
204 | sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret); | ||
205 | if (ret < 0) { | ||
206 | IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret); | ||
207 | goto release_irq; | ||
208 | } | ||
209 | |||
210 | sdio_release_host(hw->func); | ||
211 | |||
212 | IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n"); | ||
213 | |||
214 | return 0; | ||
215 | |||
216 | release_irq: | ||
217 | sdio_release_irq(hw->func); | ||
218 | release_host: | ||
219 | sdio_release_host(hw->func); | ||
220 | |||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | static int if_sdio_disable(struct iwm_priv *iwm) | ||
225 | { | ||
226 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
227 | int ret; | ||
228 | |||
229 | sdio_claim_host(hw->func); | ||
230 | sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); | ||
231 | if (ret < 0) | ||
232 | IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret); | ||
233 | |||
234 | sdio_release_irq(hw->func); | ||
235 | sdio_disable_func(hw->func); | ||
236 | sdio_release_host(hw->func); | ||
237 | |||
238 | iwm_sdio_rx_free(hw); | ||
239 | |||
240 | iwm_reset(iwm); | ||
241 | |||
242 | IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) | ||
248 | { | ||
249 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
250 | int aligned_count = ALIGN(count, hw->blk_size); | ||
251 | int ret; | ||
252 | |||
253 | if ((unsigned long)buf & 0x3) { | ||
254 | IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf); | ||
255 | /* TODO: Is this a hardware limitation? use get_unligned */ | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | |||
259 | sdio_claim_host(hw->func); | ||
260 | ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf, | ||
261 | aligned_count); | ||
262 | sdio_release_host(hw->func); | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, | ||
268 | size_t count, loff_t *ppos) | ||
269 | { | ||
270 | struct iwm_priv *iwm = filp->private_data; | ||
271 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
272 | char *buf; | ||
273 | u8 cccr; | ||
274 | int buf_len = 4096, ret; | ||
275 | size_t len = 0; | ||
276 | |||
277 | if (*ppos != 0) | ||
278 | return 0; | ||
279 | if (count < sizeof(buf)) | ||
280 | return -ENOSPC; | ||
281 | |||
282 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
283 | if (!buf) | ||
284 | return -ENOMEM; | ||
285 | |||
286 | sdio_claim_host(hw->func); | ||
287 | |||
288 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret); | ||
289 | if (ret) { | ||
290 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n"); | ||
291 | goto err; | ||
292 | } | ||
293 | len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr); | ||
294 | |||
295 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret); | ||
296 | if (ret) { | ||
297 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n"); | ||
298 | goto err; | ||
299 | } | ||
300 | len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr); | ||
301 | |||
302 | |||
303 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret); | ||
304 | if (ret) { | ||
305 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n"); | ||
306 | goto err; | ||
307 | } | ||
308 | len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr); | ||
309 | |||
310 | |||
311 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret); | ||
312 | if (ret) { | ||
313 | IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n"); | ||
314 | goto err; | ||
315 | } | ||
316 | len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr); | ||
317 | |||
318 | |||
319 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret); | ||
320 | if (ret) { | ||
321 | IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n"); | ||
322 | goto err; | ||
323 | } | ||
324 | len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr); | ||
325 | |||
326 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret); | ||
327 | if (ret) { | ||
328 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n"); | ||
329 | goto err; | ||
330 | } | ||
331 | len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr); | ||
332 | |||
333 | |||
334 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret); | ||
335 | if (ret) { | ||
336 | IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n"); | ||
337 | goto err; | ||
338 | } | ||
339 | len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr); | ||
340 | |||
341 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret); | ||
342 | if (ret) { | ||
343 | IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n"); | ||
344 | goto err; | ||
345 | } | ||
346 | len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr); | ||
347 | |||
348 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
349 | err: | ||
350 | sdio_release_host(hw->func); | ||
351 | |||
352 | kfree(buf); | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static const struct file_operations iwm_debugfs_sdio_fops = { | ||
358 | .owner = THIS_MODULE, | ||
359 | .open = simple_open, | ||
360 | .read = iwm_debugfs_sdio_read, | ||
361 | .llseek = default_llseek, | ||
362 | }; | ||
363 | |||
364 | static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) | ||
365 | { | ||
366 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
367 | |||
368 | hw->cccr_dentry = debugfs_create_file("cccr", 0200, | ||
369 | parent_dir, iwm, | ||
370 | &iwm_debugfs_sdio_fops); | ||
371 | } | ||
372 | |||
373 | static void if_sdio_debugfs_exit(struct iwm_priv *iwm) | ||
374 | { | ||
375 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
376 | |||
377 | debugfs_remove(hw->cccr_dentry); | ||
378 | } | ||
379 | |||
380 | static struct iwm_if_ops if_sdio_ops = { | ||
381 | .enable = if_sdio_enable, | ||
382 | .disable = if_sdio_disable, | ||
383 | .send_chunk = if_sdio_send_chunk, | ||
384 | .debugfs_init = if_sdio_debugfs_init, | ||
385 | .debugfs_exit = if_sdio_debugfs_exit, | ||
386 | .umac_name = "iwmc3200wifi-umac-sdio.bin", | ||
387 | .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", | ||
388 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", | ||
389 | }; | ||
390 | MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); | ||
391 | MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); | ||
392 | MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); | ||
393 | |||
394 | static int iwm_sdio_probe(struct sdio_func *func, | ||
395 | const struct sdio_device_id *id) | ||
396 | { | ||
397 | struct iwm_priv *iwm; | ||
398 | struct iwm_sdio_priv *hw; | ||
399 | struct device *dev = &func->dev; | ||
400 | int ret; | ||
401 | |||
402 | /* check if TOP has already initialized the card */ | ||
403 | sdio_claim_host(func); | ||
404 | ret = sdio_enable_func(func); | ||
405 | if (ret) { | ||
406 | dev_err(dev, "wait for TOP to enable the device\n"); | ||
407 | sdio_release_host(func); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE); | ||
412 | |||
413 | sdio_disable_func(func); | ||
414 | sdio_release_host(func); | ||
415 | |||
416 | if (ret < 0) { | ||
417 | dev_err(dev, "Failed to set block size: %d\n", ret); | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops); | ||
422 | if (IS_ERR(iwm)) { | ||
423 | dev_err(dev, "allocate SDIO interface failed\n"); | ||
424 | return PTR_ERR(iwm); | ||
425 | } | ||
426 | |||
427 | hw = iwm_private(iwm); | ||
428 | hw->iwm = iwm; | ||
429 | |||
430 | iwm_debugfs_init(iwm); | ||
431 | |||
432 | sdio_set_drvdata(func, hw); | ||
433 | |||
434 | hw->func = func; | ||
435 | hw->blk_size = IWM_SDIO_BLK_SIZE; | ||
436 | |||
437 | hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio"); | ||
438 | if (!hw->isr_wq) { | ||
439 | ret = -ENOMEM; | ||
440 | goto debugfs_exit; | ||
441 | } | ||
442 | |||
443 | INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); | ||
444 | |||
445 | ret = iwm_if_add(iwm); | ||
446 | if (ret) { | ||
447 | dev_err(dev, "add SDIO interface failed\n"); | ||
448 | goto destroy_wq; | ||
449 | } | ||
450 | |||
451 | dev_info(dev, "IWM SDIO probe\n"); | ||
452 | |||
453 | return 0; | ||
454 | |||
455 | destroy_wq: | ||
456 | destroy_workqueue(hw->isr_wq); | ||
457 | debugfs_exit: | ||
458 | iwm_debugfs_exit(iwm); | ||
459 | iwm_if_free(iwm); | ||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | static void iwm_sdio_remove(struct sdio_func *func) | ||
464 | { | ||
465 | struct iwm_sdio_priv *hw = sdio_get_drvdata(func); | ||
466 | struct iwm_priv *iwm = hw_to_iwm(hw); | ||
467 | struct device *dev = &func->dev; | ||
468 | |||
469 | iwm_if_remove(iwm); | ||
470 | destroy_workqueue(hw->isr_wq); | ||
471 | iwm_debugfs_exit(iwm); | ||
472 | iwm_if_free(iwm); | ||
473 | |||
474 | sdio_set_drvdata(func, NULL); | ||
475 | |||
476 | dev_info(dev, "IWM SDIO remove\n"); | ||
477 | } | ||
478 | |||
479 | static const struct sdio_device_id iwm_sdio_ids[] = { | ||
480 | /* Global/AGN SKU */ | ||
481 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) }, | ||
482 | /* BGN SKU */ | ||
483 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) }, | ||
484 | { /* end: all zeroes */ }, | ||
485 | }; | ||
486 | MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); | ||
487 | |||
488 | static struct sdio_driver iwm_sdio_driver = { | ||
489 | .name = "iwm_sdio", | ||
490 | .id_table = iwm_sdio_ids, | ||
491 | .probe = iwm_sdio_probe, | ||
492 | .remove = iwm_sdio_remove, | ||
493 | }; | ||
494 | |||
495 | static int __init iwm_sdio_init_module(void) | ||
496 | { | ||
497 | return sdio_register_driver(&iwm_sdio_driver); | ||
498 | } | ||
499 | |||
500 | static void __exit iwm_sdio_exit_module(void) | ||
501 | { | ||
502 | sdio_unregister_driver(&iwm_sdio_driver); | ||
503 | } | ||
504 | |||
505 | module_init(iwm_sdio_init_module); | ||
506 | module_exit(iwm_sdio_exit_module); | ||
507 | |||
508 | MODULE_LICENSE("GPL"); | ||
509 | MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR); | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h deleted file mode 100644 index aab6b6892e45..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/sdio.h +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_SDIO_H__ | ||
40 | #define __IWM_SDIO_H__ | ||
41 | |||
42 | #define IWM_SDIO_DATA_ADDR 0x0 | ||
43 | #define IWM_SDIO_INTR_ENABLE_ADDR 0x14 | ||
44 | #define IWM_SDIO_INTR_STATUS_ADDR 0x13 | ||
45 | #define IWM_SDIO_INTR_CLEAR_ADDR 0x13 | ||
46 | #define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C | ||
47 | |||
48 | #define IWM_SDIO_BLK_SIZE 256 | ||
49 | |||
50 | #define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private) | ||
51 | |||
52 | struct iwm_sdio_priv { | ||
53 | struct sdio_func *func; | ||
54 | struct iwm_priv *iwm; | ||
55 | |||
56 | struct workqueue_struct *isr_wq; | ||
57 | struct work_struct isr_worker; | ||
58 | |||
59 | struct dentry *cccr_dentry; | ||
60 | |||
61 | unsigned int blk_size; | ||
62 | }; | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.c b/drivers/net/wireless/iwmc3200wifi/trace.c deleted file mode 100644 index 904d36f22311..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/trace.c +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | #include "iwm.h" | ||
2 | #define CREATE_TRACE_POINTS | ||
3 | #include "trace.h" | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.h b/drivers/net/wireless/iwmc3200wifi/trace.h deleted file mode 100644 index f5f7070b7e22..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/trace.h +++ /dev/null | |||
@@ -1,283 +0,0 @@ | |||
1 | #if !defined(__IWM_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) | ||
2 | #define __IWM_TRACE_H__ | ||
3 | |||
4 | #include <linux/tracepoint.h> | ||
5 | |||
6 | #if !defined(CONFIG_IWM_TRACING) | ||
7 | #undef TRACE_EVENT | ||
8 | #define TRACE_EVENT(name, proto, ...) \ | ||
9 | static inline void trace_ ## name(proto) {} | ||
10 | #endif | ||
11 | |||
12 | #undef TRACE_SYSTEM | ||
13 | #define TRACE_SYSTEM iwm | ||
14 | |||
15 | #define IWM_ENTRY __array(char, ndev_name, 16) | ||
16 | #define IWM_ASSIGN strlcpy(__entry->ndev_name, iwm_to_ndev(iwm)->name, 16) | ||
17 | #define IWM_PR_FMT "%s" | ||
18 | #define IWM_PR_ARG __entry->ndev_name | ||
19 | |||
20 | TRACE_EVENT(iwm_tx_nonwifi_cmd, | ||
21 | TP_PROTO(struct iwm_priv *iwm, struct iwm_udma_out_nonwifi_hdr *hdr), | ||
22 | |||
23 | TP_ARGS(iwm, hdr), | ||
24 | |||
25 | TP_STRUCT__entry( | ||
26 | IWM_ENTRY | ||
27 | __field(u8, opcode) | ||
28 | __field(u8, resp) | ||
29 | __field(u8, eot) | ||
30 | __field(u8, hw) | ||
31 | __field(u16, seq) | ||
32 | __field(u32, addr) | ||
33 | __field(u32, op1) | ||
34 | __field(u32, op2) | ||
35 | ), | ||
36 | |||
37 | TP_fast_assign( | ||
38 | IWM_ASSIGN; | ||
39 | __entry->opcode = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE); | ||
40 | __entry->resp = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP); | ||
41 | __entry->eot = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT); | ||
42 | __entry->hw = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW); | ||
43 | __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM); | ||
44 | __entry->addr = le32_to_cpu(hdr->addr); | ||
45 | __entry->op1 = le32_to_cpu(hdr->op1_sz); | ||
46 | __entry->op2 = le32_to_cpu(hdr->op2); | ||
47 | ), | ||
48 | |||
49 | TP_printk( | ||
50 | IWM_PR_FMT " Tx TARGET CMD: opcode 0x%x, resp %d, eot %d, " | ||
51 | "hw %d, seq 0x%x, addr 0x%x, op1 0x%x, op2 0x%x", | ||
52 | IWM_PR_ARG, __entry->opcode, __entry->resp, __entry->eot, | ||
53 | __entry->hw, __entry->seq, __entry->addr, __entry->op1, | ||
54 | __entry->op2 | ||
55 | ) | ||
56 | ); | ||
57 | |||
58 | TRACE_EVENT(iwm_tx_wifi_cmd, | ||
59 | TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_out_hdr *hdr), | ||
60 | |||
61 | TP_ARGS(iwm, hdr), | ||
62 | |||
63 | TP_STRUCT__entry( | ||
64 | IWM_ENTRY | ||
65 | __field(u8, opcode) | ||
66 | __field(u8, lmac) | ||
67 | __field(u8, resp) | ||
68 | __field(u8, eot) | ||
69 | __field(u8, ra_tid) | ||
70 | __field(u8, credit_group) | ||
71 | __field(u8, color) | ||
72 | __field(u16, seq) | ||
73 | ), | ||
74 | |||
75 | TP_fast_assign( | ||
76 | IWM_ASSIGN; | ||
77 | __entry->opcode = hdr->sw_hdr.cmd.cmd; | ||
78 | __entry->lmac = 0; | ||
79 | __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num); | ||
80 | __entry->resp = GET_VAL8(hdr->sw_hdr.cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ); | ||
81 | __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR); | ||
82 | __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT); | ||
83 | __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID); | ||
84 | __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP); | ||
85 | if (__entry->opcode == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH || | ||
86 | __entry->opcode == UMAC_CMD_OPCODE_WIFI_IF_WRAPPER) { | ||
87 | __entry->lmac = 1; | ||
88 | __entry->opcode = ((struct iwm_lmac_hdr *)(hdr + 1))->id; | ||
89 | } | ||
90 | ), | ||
91 | |||
92 | TP_printk( | ||
93 | IWM_PR_FMT " Tx %cMAC CMD: opcode 0x%x, resp %d, eot %d, " | ||
94 | "seq 0x%x, sta_color 0x%x, ra_tid 0x%x, credit_group 0x%x", | ||
95 | IWM_PR_ARG, __entry->lmac ? 'L' : 'U', __entry->opcode, | ||
96 | __entry->resp, __entry->eot, __entry->seq, __entry->color, | ||
97 | __entry->ra_tid, __entry->credit_group | ||
98 | ) | ||
99 | ); | ||
100 | |||
101 | TRACE_EVENT(iwm_tx_packets, | ||
102 | TP_PROTO(struct iwm_priv *iwm, u8 *buf, int len), | ||
103 | |||
104 | TP_ARGS(iwm, buf, len), | ||
105 | |||
106 | TP_STRUCT__entry( | ||
107 | IWM_ENTRY | ||
108 | __field(u8, eot) | ||
109 | __field(u8, ra_tid) | ||
110 | __field(u8, credit_group) | ||
111 | __field(u8, color) | ||
112 | __field(u16, seq) | ||
113 | __field(u8, npkt) | ||
114 | __field(u32, bytes) | ||
115 | ), | ||
116 | |||
117 | TP_fast_assign( | ||
118 | struct iwm_umac_wifi_out_hdr *hdr = | ||
119 | (struct iwm_umac_wifi_out_hdr *)buf; | ||
120 | |||
121 | IWM_ASSIGN; | ||
122 | __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT); | ||
123 | __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID); | ||
124 | __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP); | ||
125 | __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR); | ||
126 | __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num); | ||
127 | __entry->npkt = 1; | ||
128 | __entry->bytes = len; | ||
129 | |||
130 | if (!__entry->eot) { | ||
131 | int count; | ||
132 | u8 *ptr = buf; | ||
133 | |||
134 | __entry->npkt = 0; | ||
135 | while (ptr < buf + len) { | ||
136 | count = GET_VAL32(hdr->sw_hdr.meta_data, | ||
137 | UMAC_FW_CMD_BYTE_COUNT); | ||
138 | ptr += ALIGN(sizeof(*hdr) + count, 16); | ||
139 | hdr = (struct iwm_umac_wifi_out_hdr *)ptr; | ||
140 | __entry->npkt++; | ||
141 | } | ||
142 | } | ||
143 | ), | ||
144 | |||
145 | TP_printk( | ||
146 | IWM_PR_FMT " Tx %spacket: eot %d, seq 0x%x, sta_color 0x%x, " | ||
147 | "ra_tid 0x%x, credit_group 0x%x, embedded_packets %d, %d bytes", | ||
148 | IWM_PR_ARG, !__entry->eot ? "concatenated " : "", | ||
149 | __entry->eot, __entry->seq, __entry->color, __entry->ra_tid, | ||
150 | __entry->credit_group, __entry->npkt, __entry->bytes | ||
151 | ) | ||
152 | ); | ||
153 | |||
154 | TRACE_EVENT(iwm_rx_nonwifi_cmd, | ||
155 | TP_PROTO(struct iwm_priv *iwm, void *buf, int len), | ||
156 | |||
157 | TP_ARGS(iwm, buf, len), | ||
158 | |||
159 | TP_STRUCT__entry( | ||
160 | IWM_ENTRY | ||
161 | __field(u8, opcode) | ||
162 | __field(u16, seq) | ||
163 | __field(u32, len) | ||
164 | ), | ||
165 | |||
166 | TP_fast_assign( | ||
167 | struct iwm_udma_in_hdr *hdr = buf; | ||
168 | |||
169 | IWM_ASSIGN; | ||
170 | __entry->opcode = GET_VAL32(hdr->cmd, UDMA_HDI_IN_NW_CMD_OPCODE); | ||
171 | __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); | ||
172 | __entry->len = len; | ||
173 | ), | ||
174 | |||
175 | TP_printk( | ||
176 | IWM_PR_FMT " Rx TARGET RESP: opcode 0x%x, seq 0x%x, len 0x%x", | ||
177 | IWM_PR_ARG, __entry->opcode, __entry->seq, __entry->len | ||
178 | ) | ||
179 | ); | ||
180 | |||
181 | TRACE_EVENT(iwm_rx_wifi_cmd, | ||
182 | TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_in_hdr *hdr), | ||
183 | |||
184 | TP_ARGS(iwm, hdr), | ||
185 | |||
186 | TP_STRUCT__entry( | ||
187 | IWM_ENTRY | ||
188 | __field(u8, cmd) | ||
189 | __field(u8, source) | ||
190 | __field(u16, seq) | ||
191 | __field(u32, count) | ||
192 | ), | ||
193 | |||
194 | TP_fast_assign( | ||
195 | IWM_ASSIGN; | ||
196 | __entry->cmd = hdr->sw_hdr.cmd.cmd; | ||
197 | __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
198 | __entry->count = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT); | ||
199 | __entry->seq = le16_to_cpu(hdr->sw_hdr.cmd.seq_num); | ||
200 | ), | ||
201 | |||
202 | TP_printk( | ||
203 | IWM_PR_FMT " Rx %s RESP: cmd 0x%x, seq 0x%x, count 0x%x", | ||
204 | IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? "LMAC" : | ||
205 | __entry->source == UMAC_HDI_IN_SOURCE_FW ? "UMAC" : "UDMA", | ||
206 | __entry->cmd, __entry->seq, __entry->count | ||
207 | ) | ||
208 | ); | ||
209 | |||
210 | #define iwm_ticket_action_symbol \ | ||
211 | { IWM_RX_TICKET_DROP, "DROP" }, \ | ||
212 | { IWM_RX_TICKET_RELEASE, "RELEASE" }, \ | ||
213 | { IWM_RX_TICKET_SNIFFER, "SNIFFER" }, \ | ||
214 | { IWM_RX_TICKET_ENQUEUE, "ENQUEUE" } | ||
215 | |||
216 | TRACE_EVENT(iwm_rx_ticket, | ||
217 | TP_PROTO(struct iwm_priv *iwm, void *buf, int len), | ||
218 | |||
219 | TP_ARGS(iwm, buf, len), | ||
220 | |||
221 | TP_STRUCT__entry( | ||
222 | IWM_ENTRY | ||
223 | __field(u8, action) | ||
224 | __field(u8, reason) | ||
225 | __field(u16, id) | ||
226 | __field(u16, flags) | ||
227 | ), | ||
228 | |||
229 | TP_fast_assign( | ||
230 | struct iwm_rx_ticket *ticket = | ||
231 | ((struct iwm_umac_notif_rx_ticket *)buf)->tickets; | ||
232 | |||
233 | IWM_ASSIGN; | ||
234 | __entry->id = le16_to_cpu(ticket->id); | ||
235 | __entry->action = le16_to_cpu(ticket->action); | ||
236 | __entry->flags = le16_to_cpu(ticket->flags); | ||
237 | __entry->reason = (__entry->flags & IWM_RX_TICKET_DROP_REASON_MSK) >> IWM_RX_TICKET_DROP_REASON_POS; | ||
238 | ), | ||
239 | |||
240 | TP_printk( | ||
241 | IWM_PR_FMT " Rx ticket: id 0x%x, action %s, %s 0x%x%s", | ||
242 | IWM_PR_ARG, __entry->id, | ||
243 | __print_symbolic(__entry->action, iwm_ticket_action_symbol), | ||
244 | __entry->reason ? "reason" : "flags", | ||
245 | __entry->reason ? __entry->reason : __entry->flags, | ||
246 | __entry->flags & IWM_RX_TICKET_AMSDU_MSK ? ", AMSDU frame" : "" | ||
247 | ) | ||
248 | ); | ||
249 | |||
250 | TRACE_EVENT(iwm_rx_packet, | ||
251 | TP_PROTO(struct iwm_priv *iwm, void *buf, int len), | ||
252 | |||
253 | TP_ARGS(iwm, buf, len), | ||
254 | |||
255 | TP_STRUCT__entry( | ||
256 | IWM_ENTRY | ||
257 | __field(u8, source) | ||
258 | __field(u16, id) | ||
259 | __field(u32, len) | ||
260 | ), | ||
261 | |||
262 | TP_fast_assign( | ||
263 | struct iwm_umac_wifi_in_hdr *hdr = buf; | ||
264 | |||
265 | IWM_ASSIGN; | ||
266 | __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
267 | __entry->id = le16_to_cpu(hdr->sw_hdr.cmd.seq_num); | ||
268 | __entry->len = len - sizeof(*hdr); | ||
269 | ), | ||
270 | |||
271 | TP_printk( | ||
272 | IWM_PR_FMT " Rx %s packet: id 0x%x, %d bytes", | ||
273 | IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? | ||
274 | "LMAC" : "UMAC", __entry->id, __entry->len | ||
275 | ) | ||
276 | ); | ||
277 | #endif | ||
278 | |||
279 | #undef TRACE_INCLUDE_PATH | ||
280 | #define TRACE_INCLUDE_PATH . | ||
281 | #undef TRACE_INCLUDE_FILE | ||
282 | #define TRACE_INCLUDE_FILE trace | ||
283 | #include <trace/define_trace.h> | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c deleted file mode 100644 index be98074c0608..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ /dev/null | |||
@@ -1,529 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * iwm Tx theory of operation: | ||
41 | * | ||
42 | * 1) We receive a 802.3 frame from the stack | ||
43 | * 2) We convert it to a 802.11 frame [iwm_xmit_frame] | ||
44 | * 3) We queue it to its corresponding tx queue [iwm_xmit_frame] | ||
45 | * 4) We schedule the tx worker. There is one worker per tx | ||
46 | * queue. [iwm_xmit_frame] | ||
47 | * 5) The tx worker is scheduled | ||
48 | * 6) We go through every queued skb on the tx queue, and for each | ||
49 | * and every one of them: [iwm_tx_worker] | ||
50 | * a) We check if we have enough Tx credits (see below for a Tx | ||
51 | * credits description) for the frame length. [iwm_tx_worker] | ||
52 | * b) If we do, we aggregate the Tx frame into a UDMA one, by | ||
53 | * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker] | ||
54 | * c) When we run out of credits, or when we reach the maximum | ||
55 | * concatenation size, we actually send the concatenated UDMA | ||
56 | * frame. [iwm_tx_worker] | ||
57 | * | ||
58 | * When we run out of Tx credits, the skbs are filling the tx queue, | ||
59 | * and eventually we will stop the netdev queue. [iwm_tx_worker] | ||
60 | * The tx queue is emptied as we're getting new tx credits, by | ||
61 | * scheduling the tx_worker. [iwm_tx_credit_inc] | ||
62 | * The netdev queue is started again when we have enough tx credits, | ||
63 | * and when our tx queue has some reasonable amout of space available | ||
64 | * (i.e. half of the max size). [iwm_tx_worker] | ||
65 | */ | ||
66 | |||
67 | #include <linux/slab.h> | ||
68 | #include <linux/skbuff.h> | ||
69 | #include <linux/netdevice.h> | ||
70 | #include <linux/ieee80211.h> | ||
71 | |||
72 | #include "iwm.h" | ||
73 | #include "debug.h" | ||
74 | #include "commands.h" | ||
75 | #include "hal.h" | ||
76 | #include "umac.h" | ||
77 | #include "bus.h" | ||
78 | |||
79 | #define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff | ||
80 | |||
81 | #define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \ | ||
82 | (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0)) | ||
83 | |||
84 | #define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1) | ||
85 | #define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1) | ||
86 | |||
87 | /* require to hold tx_credit lock */ | ||
88 | static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id) | ||
89 | { | ||
90 | struct pool_entry *pool = &tx_credit->pools[id]; | ||
91 | struct spool_entry *spool = &tx_credit->spools[pool->sid]; | ||
92 | int spool_pages; | ||
93 | |||
94 | /* number of pages can be taken from spool by this pool */ | ||
95 | spool_pages = spool->max_pages - spool->alloc_pages + | ||
96 | max(pool->min_pages - pool->alloc_pages, 0); | ||
97 | |||
98 | return min(pool->max_pages - pool->alloc_pages, spool_pages); | ||
99 | } | ||
100 | |||
101 | static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb) | ||
102 | { | ||
103 | u32 npages = BYTES_TO_PAGES(nb); | ||
104 | |||
105 | if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id)) | ||
106 | return 1; | ||
107 | |||
108 | set_bit(id, &iwm->tx_credit.full_pools_map); | ||
109 | |||
110 | IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n", | ||
111 | pool_id_to_queue(id), | ||
112 | iwm_tx_credit_get(&iwm->tx_credit, id)); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages) | ||
118 | { | ||
119 | struct pool_entry *pool; | ||
120 | struct spool_entry *spool; | ||
121 | int freed_pages; | ||
122 | int queue; | ||
123 | |||
124 | BUG_ON(id >= IWM_MACS_OUT_GROUPS); | ||
125 | |||
126 | pool = &iwm->tx_credit.pools[id]; | ||
127 | spool = &iwm->tx_credit.spools[pool->sid]; | ||
128 | |||
129 | freed_pages = total_freed_pages - pool->total_freed_pages; | ||
130 | IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id); | ||
131 | |||
132 | if (!freed_pages) { | ||
133 | IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n"); | ||
134 | return; | ||
135 | } else if (freed_pages < 0) | ||
136 | freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1; | ||
137 | |||
138 | if (pool->alloc_pages > pool->min_pages) { | ||
139 | int spool_pages = pool->alloc_pages - pool->min_pages; | ||
140 | spool_pages = min(spool_pages, freed_pages); | ||
141 | spool->alloc_pages -= spool_pages; | ||
142 | } | ||
143 | |||
144 | pool->alloc_pages -= freed_pages; | ||
145 | pool->total_freed_pages = total_freed_pages; | ||
146 | |||
147 | IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " | ||
148 | "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, | ||
149 | pool->total_freed_pages, pool->sid, spool->alloc_pages); | ||
150 | |||
151 | if (test_bit(id, &iwm->tx_credit.full_pools_map) && | ||
152 | (pool->alloc_pages < pool->max_pages / 2)) { | ||
153 | clear_bit(id, &iwm->tx_credit.full_pools_map); | ||
154 | |||
155 | queue = pool_id_to_queue(id); | ||
156 | |||
157 | IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available " | ||
158 | "credit: %d\n", queue, | ||
159 | iwm_tx_credit_get(&iwm->tx_credit, id)); | ||
160 | queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages) | ||
165 | { | ||
166 | struct pool_entry *pool; | ||
167 | struct spool_entry *spool; | ||
168 | int spool_pages; | ||
169 | |||
170 | IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n", | ||
171 | alloc_pages, id); | ||
172 | |||
173 | BUG_ON(id >= IWM_MACS_OUT_GROUPS); | ||
174 | |||
175 | pool = &iwm->tx_credit.pools[id]; | ||
176 | spool = &iwm->tx_credit.spools[pool->sid]; | ||
177 | |||
178 | spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages; | ||
179 | |||
180 | if (pool->alloc_pages >= pool->min_pages) | ||
181 | spool->alloc_pages += alloc_pages; | ||
182 | else if (spool_pages > 0) | ||
183 | spool->alloc_pages += spool_pages; | ||
184 | |||
185 | pool->alloc_pages += alloc_pages; | ||
186 | |||
187 | IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " | ||
188 | "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, | ||
189 | pool->total_freed_pages, pool->sid, spool->alloc_pages); | ||
190 | } | ||
191 | |||
192 | int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) | ||
193 | { | ||
194 | u32 npages = BYTES_TO_PAGES(nb); | ||
195 | int ret = 0; | ||
196 | |||
197 | spin_lock(&iwm->tx_credit.lock); | ||
198 | |||
199 | if (!iwm_tx_credit_ok(iwm, id, nb)) { | ||
200 | IWM_DBG_TX(iwm, DBG, "No credit available for pool[%d]\n", id); | ||
201 | ret = -ENOSPC; | ||
202 | goto out; | ||
203 | } | ||
204 | |||
205 | iwm_tx_credit_dec(iwm, id, npages); | ||
206 | |||
207 | out: | ||
208 | spin_unlock(&iwm->tx_credit.lock); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Since we're on an SDIO or USB bus, we are not sharing memory | ||
214 | * for storing to be transmitted frames. The host needs to push | ||
215 | * them upstream. As a consequence there needs to be a way for | ||
216 | * the target to let us know if it can actually take more TX frames | ||
217 | * or not. This is what Tx credits are for. | ||
218 | * | ||
219 | * For each Tx HW queue, we have a Tx pool, and then we have one | ||
220 | * unique super pool (spool), which is actually a global pool of | ||
221 | * all the UMAC pages. | ||
222 | * For each Tx pool we have a min_pages, a max_pages fields, and a | ||
223 | * alloc_pages fields. The alloc_pages tracks the number of pages | ||
224 | * currently allocated from the tx pool. | ||
225 | * Here are the rules to check if given a tx frame we have enough | ||
226 | * tx credits for it: | ||
227 | * 1) We translate the frame length into a number of UMAC pages. | ||
228 | * Let's call them n_pages. | ||
229 | * 2) For the corresponding tx pool, we check if n_pages + | ||
230 | * pool->alloc_pages is higher than pool->min_pages. min_pages | ||
231 | * represent a set of pre-allocated pages on the tx pool. If | ||
232 | * that's the case, then we need to allocate those pages from | ||
233 | * the spool. We can do so until we reach spool->max_pages. | ||
234 | * 3) Each tx pool is not allowed to allocate more than pool->max_pages | ||
235 | * from the spool, so once we're over min_pages, we can allocate | ||
236 | * pages from the spool, but not more than max_pages. | ||
237 | * | ||
238 | * When the tx code path needs to send a tx frame, it checks first | ||
239 | * if it has enough tx credits, following those rules. [iwm_tx_credit_get] | ||
240 | * If it does, it then updates the pool and spool counters and | ||
241 | * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec] | ||
242 | * On the other side, when the UMAC is done transmitting frames, it | ||
243 | * will send a credit update notification to the host. This is when | ||
244 | * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc, | ||
245 | * called from rx.c:iwm_ntf_tx_credit_update] | ||
246 | * | ||
247 | */ | ||
248 | void iwm_tx_credit_init_pools(struct iwm_priv *iwm, | ||
249 | struct iwm_umac_notif_alive *alive) | ||
250 | { | ||
251 | int i, sid, pool_pages; | ||
252 | |||
253 | spin_lock(&iwm->tx_credit.lock); | ||
254 | |||
255 | iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count); | ||
256 | iwm->tx_credit.full_pools_map = 0; | ||
257 | memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry)); | ||
258 | |||
259 | IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr); | ||
260 | |||
261 | for (i = 0; i < iwm->tx_credit.pool_nr; i++) { | ||
262 | __le32 page_grp_state = alive->page_grp_state[i]; | ||
263 | |||
264 | iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state, | ||
265 | UMAC_ALIVE_PAGE_STS_GRP_NUM); | ||
266 | iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state, | ||
267 | UMAC_ALIVE_PAGE_STS_SGRP_NUM); | ||
268 | iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state, | ||
269 | UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE); | ||
270 | iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state, | ||
271 | UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE); | ||
272 | iwm->tx_credit.pools[i].alloc_pages = 0; | ||
273 | iwm->tx_credit.pools[i].total_freed_pages = 0; | ||
274 | |||
275 | sid = iwm->tx_credit.pools[i].sid; | ||
276 | pool_pages = iwm->tx_credit.pools[i].min_pages; | ||
277 | |||
278 | if (iwm->tx_credit.spools[sid].max_pages == 0) { | ||
279 | iwm->tx_credit.spools[sid].id = sid; | ||
280 | iwm->tx_credit.spools[sid].max_pages = | ||
281 | GET_VAL32(page_grp_state, | ||
282 | UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE); | ||
283 | iwm->tx_credit.spools[sid].alloc_pages = 0; | ||
284 | } | ||
285 | |||
286 | iwm->tx_credit.spools[sid].alloc_pages += pool_pages; | ||
287 | |||
288 | IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity " | ||
289 | "min: %d, max: %d, pool alloc: %d, total_free: %d, " | ||
290 | "super poll alloc: %d\n", | ||
291 | i, iwm->tx_credit.pools[i].id, | ||
292 | iwm->tx_credit.pools[i].sid, | ||
293 | iwm->tx_credit.pools[i].min_pages, | ||
294 | iwm->tx_credit.pools[i].max_pages, | ||
295 | iwm->tx_credit.pools[i].alloc_pages, | ||
296 | iwm->tx_credit.pools[i].total_freed_pages, | ||
297 | iwm->tx_credit.spools[sid].alloc_pages); | ||
298 | } | ||
299 | |||
300 | spin_unlock(&iwm->tx_credit.lock); | ||
301 | } | ||
302 | |||
303 | #define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr) | ||
304 | |||
305 | static __le16 iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, | ||
306 | int pool_id, u8 *buf) | ||
307 | { | ||
308 | struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf; | ||
309 | struct iwm_udma_wifi_cmd udma_cmd; | ||
310 | struct iwm_umac_cmd umac_cmd; | ||
311 | struct iwm_tx_info *tx_info = skb_to_tx_info(skb); | ||
312 | |||
313 | udma_cmd.count = cpu_to_le16(skb->len + | ||
314 | sizeof(struct iwm_umac_fw_cmd_hdr)); | ||
315 | /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be | ||
316 | * called later to set EOP for the last packet. */ | ||
317 | udma_cmd.eop = 0; | ||
318 | udma_cmd.credit_group = pool_id; | ||
319 | udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; | ||
320 | udma_cmd.lmac_offset = 0; | ||
321 | |||
322 | umac_cmd.id = REPLY_TX; | ||
323 | umac_cmd.count = cpu_to_le16(skb->len); | ||
324 | umac_cmd.color = tx_info->color; | ||
325 | umac_cmd.resp = 0; | ||
326 | umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm)); | ||
327 | |||
328 | iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd); | ||
329 | iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd); | ||
330 | |||
331 | memcpy(buf + sizeof(*hdr), skb->data, skb->len); | ||
332 | |||
333 | return umac_cmd.seq_num; | ||
334 | } | ||
335 | |||
336 | static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, | ||
337 | struct iwm_tx_queue *txq) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | if (!txq->concat_count) | ||
342 | return 0; | ||
343 | |||
344 | IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n", | ||
345 | txq->id, txq->concat_count); | ||
346 | |||
347 | /* mark EOP for the last packet */ | ||
348 | iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1); | ||
349 | |||
350 | trace_iwm_tx_packets(iwm, txq->concat_buf, txq->concat_count); | ||
351 | ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count); | ||
352 | |||
353 | txq->concat_count = 0; | ||
354 | txq->concat_ptr = txq->concat_buf; | ||
355 | |||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | void iwm_tx_worker(struct work_struct *work) | ||
360 | { | ||
361 | struct iwm_priv *iwm; | ||
362 | struct iwm_tx_info *tx_info = NULL; | ||
363 | struct sk_buff *skb; | ||
364 | struct iwm_tx_queue *txq; | ||
365 | struct iwm_sta_info *sta_info; | ||
366 | struct iwm_tid_info *tid_info; | ||
367 | int cmdlen, ret, pool_id; | ||
368 | |||
369 | txq = container_of(work, struct iwm_tx_queue, worker); | ||
370 | iwm = container_of(txq, struct iwm_priv, txq[txq->id]); | ||
371 | |||
372 | pool_id = queue_to_pool_id(txq->id); | ||
373 | |||
374 | while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && | ||
375 | !skb_queue_empty(&txq->queue)) { | ||
376 | |||
377 | spin_lock_bh(&txq->lock); | ||
378 | skb = skb_dequeue(&txq->queue); | ||
379 | spin_unlock_bh(&txq->lock); | ||
380 | |||
381 | tx_info = skb_to_tx_info(skb); | ||
382 | sta_info = &iwm->sta_table[tx_info->sta]; | ||
383 | if (!sta_info->valid) { | ||
384 | IWM_ERR(iwm, "Trying to send a frame to unknown STA\n"); | ||
385 | kfree_skb(skb); | ||
386 | continue; | ||
387 | } | ||
388 | |||
389 | tid_info = &sta_info->tid_info[tx_info->tid]; | ||
390 | |||
391 | mutex_lock(&tid_info->mutex); | ||
392 | |||
393 | /* | ||
394 | * If the RAxTID is stopped, we queue the skb to the stopped | ||
395 | * queue. | ||
396 | * Whenever we'll get a UMAC notification to resume the tx flow | ||
397 | * for this RAxTID, we'll merge back the stopped queue into the | ||
398 | * regular queue. See iwm_ntf_stop_resume_tx() from rx.c. | ||
399 | */ | ||
400 | if (tid_info->stopped) { | ||
401 | IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n", | ||
402 | tx_info->sta, tx_info->tid); | ||
403 | spin_lock_bh(&txq->lock); | ||
404 | skb_queue_tail(&txq->stopped_queue, skb); | ||
405 | spin_unlock_bh(&txq->lock); | ||
406 | |||
407 | mutex_unlock(&tid_info->mutex); | ||
408 | continue; | ||
409 | } | ||
410 | |||
411 | cmdlen = IWM_UDMA_HDR_LEN + skb->len; | ||
412 | |||
413 | IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " | ||
414 | "%d, color: %d\n", txq->id, skb, tx_info->sta, | ||
415 | tx_info->color); | ||
416 | |||
417 | if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) | ||
418 | iwm_tx_send_concat_packets(iwm, txq); | ||
419 | |||
420 | ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen); | ||
421 | if (ret) { | ||
422 | IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " | ||
423 | "%d, Tx worker stopped\n", txq->id); | ||
424 | spin_lock_bh(&txq->lock); | ||
425 | skb_queue_head(&txq->queue, skb); | ||
426 | spin_unlock_bh(&txq->lock); | ||
427 | |||
428 | mutex_unlock(&tid_info->mutex); | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | txq->concat_ptr = txq->concat_buf + txq->concat_count; | ||
433 | tid_info->last_seq_num = | ||
434 | iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); | ||
435 | txq->concat_count += ALIGN(cmdlen, 16); | ||
436 | |||
437 | mutex_unlock(&tid_info->mutex); | ||
438 | |||
439 | kfree_skb(skb); | ||
440 | } | ||
441 | |||
442 | iwm_tx_send_concat_packets(iwm, txq); | ||
443 | |||
444 | if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) && | ||
445 | !test_bit(pool_id, &iwm->tx_credit.full_pools_map) && | ||
446 | (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) { | ||
447 | IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id); | ||
448 | netif_wake_subqueue(iwm_to_ndev(iwm), txq->id); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | ||
453 | { | ||
454 | struct iwm_priv *iwm = ndev_to_iwm(netdev); | ||
455 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
456 | struct iwm_tx_info *tx_info; | ||
457 | struct iwm_tx_queue *txq; | ||
458 | struct iwm_sta_info *sta_info; | ||
459 | u8 *dst_addr, sta_id; | ||
460 | u16 queue; | ||
461 | int ret; | ||
462 | |||
463 | |||
464 | if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
465 | IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " | ||
466 | "not associated\n"); | ||
467 | netif_tx_stop_all_queues(netdev); | ||
468 | goto drop; | ||
469 | } | ||
470 | |||
471 | queue = skb_get_queue_mapping(skb); | ||
472 | BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */ | ||
473 | |||
474 | txq = &iwm->txq[queue]; | ||
475 | |||
476 | /* No free space for Tx, tx_worker is too slow */ | ||
477 | if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) || | ||
478 | (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) { | ||
479 | IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); | ||
480 | netif_stop_subqueue(netdev, queue); | ||
481 | return NETDEV_TX_BUSY; | ||
482 | } | ||
483 | |||
484 | ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype, | ||
485 | iwm->bssid, 0); | ||
486 | if (ret) { | ||
487 | IWM_ERR(iwm, "build wifi header failed\n"); | ||
488 | goto drop; | ||
489 | } | ||
490 | |||
491 | dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1; | ||
492 | |||
493 | for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) { | ||
494 | sta_info = &iwm->sta_table[sta_id]; | ||
495 | if (sta_info->valid && | ||
496 | !memcmp(dst_addr, sta_info->addr, ETH_ALEN)) | ||
497 | break; | ||
498 | } | ||
499 | |||
500 | if (sta_id == IWM_STA_TABLE_NUM) { | ||
501 | IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n", | ||
502 | dst_addr); | ||
503 | goto drop; | ||
504 | } | ||
505 | |||
506 | tx_info = skb_to_tx_info(skb); | ||
507 | tx_info->sta = sta_id; | ||
508 | tx_info->color = sta_info->color; | ||
509 | /* UMAC uses TID 8 (vs. 0) for non QoS packets */ | ||
510 | if (sta_info->qos) | ||
511 | tx_info->tid = skb->priority; | ||
512 | else | ||
513 | tx_info->tid = IWM_UMAC_MGMT_TID; | ||
514 | |||
515 | spin_lock_bh(&iwm->txq[queue].lock); | ||
516 | skb_queue_tail(&iwm->txq[queue].queue, skb); | ||
517 | spin_unlock_bh(&iwm->txq[queue].lock); | ||
518 | |||
519 | queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); | ||
520 | |||
521 | netdev->stats.tx_packets++; | ||
522 | netdev->stats.tx_bytes += skb->len; | ||
523 | return NETDEV_TX_OK; | ||
524 | |||
525 | drop: | ||
526 | netdev->stats.tx_dropped++; | ||
527 | dev_kfree_skb_any(skb); | ||
528 | return NETDEV_TX_OK; | ||
529 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h deleted file mode 100644 index 4a137d334a42..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ /dev/null | |||
@@ -1,789 +0,0 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_UMAC_H__ | ||
40 | #define __IWM_UMAC_H__ | ||
41 | |||
42 | struct iwm_udma_in_hdr { | ||
43 | __le32 cmd; | ||
44 | __le32 size; | ||
45 | } __packed; | ||
46 | |||
47 | struct iwm_udma_out_nonwifi_hdr { | ||
48 | __le32 cmd; | ||
49 | __le32 addr; | ||
50 | __le32 op1_sz; | ||
51 | __le32 op2; | ||
52 | } __packed; | ||
53 | |||
54 | struct iwm_udma_out_wifi_hdr { | ||
55 | __le32 cmd; | ||
56 | __le32 meta_data; | ||
57 | } __packed; | ||
58 | |||
59 | /* Sequence numbering */ | ||
60 | #define UMAC_WIFI_SEQ_NUM_BASE 1 | ||
61 | #define UMAC_WIFI_SEQ_NUM_MAX 0x4000 | ||
62 | #define UMAC_NONWIFI_SEQ_NUM_BASE 1 | ||
63 | #define UMAC_NONWIFI_SEQ_NUM_MAX 0x10 | ||
64 | |||
65 | /* MAC address address */ | ||
66 | #define WICO_MAC_ADDRESS_ADDR 0x604008F8 | ||
67 | |||
68 | /* RA / TID */ | ||
69 | #define UMAC_HDI_ACT_TBL_IDX_TID_POS 0 | ||
70 | #define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF | ||
71 | |||
72 | #define UMAC_HDI_ACT_TBL_IDX_RA_POS 4 | ||
73 | #define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF | ||
74 | |||
75 | #define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF | ||
76 | #define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9 | ||
77 | #define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA | ||
78 | |||
79 | #define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \ | ||
80 | ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ | ||
81 | (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) | ||
82 | #define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \ | ||
83 | ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ | ||
84 | (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) | ||
85 | |||
86 | /* STA ID and color */ | ||
87 | #define STA_ID_SEED (0x0f) | ||
88 | #define STA_ID_POS (0) | ||
89 | #define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) | ||
90 | |||
91 | #define STA_COLOR_SEED (0x7) | ||
92 | #define STA_COLOR_POS (4) | ||
93 | #define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) | ||
94 | |||
95 | #define STA_ID_N_COLOR_COLOR(id_n_color) \ | ||
96 | (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) | ||
97 | #define STA_ID_N_COLOR_ID(id_n_color) \ | ||
98 | (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) | ||
99 | |||
100 | /* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ | ||
101 | #define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 | ||
102 | #define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF | ||
103 | |||
104 | /* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */ | ||
105 | #define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4 | ||
106 | #define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF | ||
107 | |||
108 | /* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */ | ||
109 | #define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8 | ||
110 | #define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF | ||
111 | |||
112 | /* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */ | ||
113 | #define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16 | ||
114 | #define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF | ||
115 | |||
116 | /* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */ | ||
117 | #define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24 | ||
118 | #define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF | ||
119 | |||
120 | /* Barkers */ | ||
121 | #define UMAC_REBOOT_BARKER 0xdeadbeef | ||
122 | #define UMAC_ACK_BARKER 0xfeedbabe | ||
123 | #define UMAC_PAD_TERMINAL 0xadadadad | ||
124 | |||
125 | /* UMAC JMP address */ | ||
126 | #define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000 | ||
127 | |||
128 | /* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */ | ||
129 | #define UMAC_HDI_OUT_CMD_OPCODE_POS 0 | ||
130 | #define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF | ||
131 | |||
132 | /* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */ | ||
133 | #define UMAC_HDI_OUT_CMD_EOT_POS 10 | ||
134 | #define UMAC_HDI_OUT_CMD_EOT_SEED 0x1 | ||
135 | |||
136 | /* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */ | ||
137 | #define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11 | ||
138 | #define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1 | ||
139 | |||
140 | /* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ | ||
141 | #define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 | ||
142 | #define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF | ||
143 | |||
144 | /* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */ | ||
145 | #define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16 | ||
146 | #define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF | ||
147 | |||
148 | /* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */ | ||
149 | #define UMAC_HDI_OUT_BYTE_COUNT_POS 0 | ||
150 | #define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF | ||
151 | |||
152 | /* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */ | ||
153 | #define UMAC_HDI_OUT_CREDIT_GRP_POS 12 | ||
154 | #define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF | ||
155 | |||
156 | /* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */ | ||
157 | #define UMAC_HDI_OUT_RATID_POS 16 | ||
158 | #define UMAC_HDI_OUT_RATID_SEED 0xFF | ||
159 | |||
160 | /* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */ | ||
161 | #define UMAC_HDI_OUT_LMAC_OFFSET_POS 24 | ||
162 | #define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF | ||
163 | |||
164 | /* Signature */ | ||
165 | #define UMAC_HDI_OUT_SIGNATURE 0xCBBC | ||
166 | |||
167 | /* buffer alignment */ | ||
168 | #define UMAC_HDI_BUF_ALIGN_MSK 0xF | ||
169 | |||
170 | /* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */ | ||
171 | #define UMAC_HDI_IN_CMD_OPCODE_POS 0 | ||
172 | #define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF | ||
173 | |||
174 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */ | ||
175 | #define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4 | ||
176 | #define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7 | ||
177 | |||
178 | /* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */ | ||
179 | #define UMAC_HDI_IN_CMD_SOURCE_POS 4 | ||
180 | #define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3 | ||
181 | |||
182 | /* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */ | ||
183 | #define UMAC_HDI_IN_CMD_EOT_POS 6 | ||
184 | #define UMAC_HDI_IN_CMD_EOT_SEED 0x1 | ||
185 | |||
186 | /* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */ | ||
187 | #define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7 | ||
188 | #define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1 | ||
189 | |||
190 | /* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */ | ||
191 | #define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8 | ||
192 | #define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1 | ||
193 | |||
194 | /* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */ | ||
195 | #define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9 | ||
196 | #define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF | ||
197 | |||
198 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ | ||
199 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 | ||
200 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF | ||
201 | |||
202 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */ | ||
203 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16 | ||
204 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF | ||
205 | |||
206 | /* Fixed Non-WiFi signature */ | ||
207 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC | ||
208 | |||
209 | /* IN NTFY op-codes */ | ||
210 | #define UMAC_NOTIFY_OPCODE_ALIVE 0xA1 | ||
211 | #define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2 | ||
212 | #define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3 | ||
213 | #define UMAC_NOTIFY_OPCODE_ERROR 0xA4 | ||
214 | #define UMAC_NOTIFY_OPCODE_DEBUG 0xA5 | ||
215 | #define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0 | ||
216 | #define UMAC_NOTIFY_OPCODE_STATS 0xB1 | ||
217 | #define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3 | ||
218 | #define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4 | ||
219 | #define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\ | ||
220 | UMAC_NOTIFY_OPCODE_ALIVE + 1) | ||
221 | #define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE) | ||
222 | |||
223 | /* HDI OUT OP CODE */ | ||
224 | #define UMAC_HDI_OUT_OPCODE_PING 0x0 | ||
225 | #define UMAC_HDI_OUT_OPCODE_READ 0x1 | ||
226 | #define UMAC_HDI_OUT_OPCODE_WRITE 0x2 | ||
227 | #define UMAC_HDI_OUT_OPCODE_JUMP 0x3 | ||
228 | #define UMAC_HDI_OUT_OPCODE_REBOOT 0x4 | ||
229 | #define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5 | ||
230 | #define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6 | ||
231 | #define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7 | ||
232 | /* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */ | ||
233 | #define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB | ||
234 | #define UMAC_HDI_OUT_OPCODE_WIFI 0xF | ||
235 | |||
236 | /* HDI IN OP CODE -- Non WiFi*/ | ||
237 | #define UMAC_HDI_IN_OPCODE_PING 0x0 | ||
238 | #define UMAC_HDI_IN_OPCODE_READ 0x1 | ||
239 | #define UMAC_HDI_IN_OPCODE_WRITE 0x2 | ||
240 | #define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5 | ||
241 | #define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6 | ||
242 | #define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7 | ||
243 | #define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8 | ||
244 | #define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9 | ||
245 | #define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA | ||
246 | #define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB | ||
247 | #define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \ | ||
248 | (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1) | ||
249 | #define UMAC_HDI_IN_OPCODE_WIFI 0xF | ||
250 | |||
251 | /* HDI IN SOURCE */ | ||
252 | #define UMAC_HDI_IN_SOURCE_FHRX 0x0 | ||
253 | #define UMAC_HDI_IN_SOURCE_UDMA 0x1 | ||
254 | #define UMAC_HDI_IN_SOURCE_FW 0x2 | ||
255 | #define UMAC_HDI_IN_SOURCE_RESERVED 0x3 | ||
256 | |||
257 | /* OUT CMD op-codes */ | ||
258 | #define UMAC_CMD_OPCODE_ECHO 0x01 | ||
259 | #define UMAC_CMD_OPCODE_HALT 0x02 | ||
260 | #define UMAC_CMD_OPCODE_RESET 0x03 | ||
261 | #define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09 | ||
262 | #define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A | ||
263 | #define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B | ||
264 | #define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C | ||
265 | #define UMAC_CMD_OPCODE_TX_ECHO 0x0D | ||
266 | #define UMAC_CMD_OPCODE_DBG_MON 0x0E | ||
267 | #define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F | ||
268 | #define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10 | ||
269 | #define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11 | ||
270 | #define UMAC_CMD_OPCODE_GET_PARAM 0x12 | ||
271 | #define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13 | ||
272 | #define UMAC_CMD_OPCODE_TARGET 0x14 | ||
273 | #define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15 | ||
274 | #define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 | ||
275 | #define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 | ||
276 | #define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 | ||
277 | #define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19 | ||
278 | #define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A | ||
279 | |||
280 | #define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA | ||
281 | #define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB | ||
282 | #define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC | ||
283 | #define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD | ||
284 | #define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE | ||
285 | #define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF | ||
286 | |||
287 | /* UMAC WiFi interface op-codes */ | ||
288 | #define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11 | ||
289 | #define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12 | ||
290 | #define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13 | ||
291 | #define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14 | ||
292 | #define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15 | ||
293 | #define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16 | ||
294 | #define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17 | ||
295 | #define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18 | ||
296 | #define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19 | ||
297 | #define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A | ||
298 | #define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B | ||
299 | #define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C | ||
300 | #define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E | ||
301 | #define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F | ||
302 | #define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 | ||
303 | |||
304 | /* UMAC WiFi interface ports */ | ||
305 | #define UMAC_WIFI_IF_FLG_PORT_DEF 0x00 | ||
306 | #define UMAC_WIFI_IF_FLG_PORT_PAN 0x01 | ||
307 | #define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF | ||
308 | |||
309 | /* UMAC WiFi interface actions */ | ||
310 | #define UMAC_WIFI_IF_FLG_ACT_GET 0x10 | ||
311 | #define UMAC_WIFI_IF_FLG_ACT_SET 0x20 | ||
312 | |||
313 | /* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */ | ||
314 | #define UMAC_FW_CMD_BYTE_COUNT_POS 0 | ||
315 | #define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF | ||
316 | |||
317 | /* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */ | ||
318 | #define UMAC_FW_CMD_STATUS_POS 12 | ||
319 | #define UMAC_FW_CMD_STATUS_SEED 0xF | ||
320 | |||
321 | /* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */ | ||
322 | #define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16 | ||
323 | #define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1 | ||
324 | |||
325 | /* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */ | ||
326 | #define UMAC_FW_CMD_TX_FW_CMD_POS 17 | ||
327 | #define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1 | ||
328 | |||
329 | /* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */ | ||
330 | #define UMAC_FW_CMD_TX_PLAINTEXT_POS 18 | ||
331 | #define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1 | ||
332 | |||
333 | /* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */ | ||
334 | #define UMAC_FW_CMD_TX_STA_COLOR_POS 20 | ||
335 | #define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7 | ||
336 | |||
337 | /* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */ | ||
338 | #define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24 | ||
339 | #define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF | ||
340 | |||
341 | /* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */ | ||
342 | #define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5 | ||
343 | #define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1 | ||
344 | |||
345 | /* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */ | ||
346 | #define UMAC_DEV_CMD_FLAGS_ABORT_POS 6 | ||
347 | #define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1 | ||
348 | |||
349 | /* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */ | ||
350 | #define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7 | ||
351 | #define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1 | ||
352 | |||
353 | /* Rx */ | ||
354 | /* Rx actions */ | ||
355 | #define IWM_RX_TICKET_DROP 0x0 | ||
356 | #define IWM_RX_TICKET_RELEASE 0x1 | ||
357 | #define IWM_RX_TICKET_SNIFFER 0x2 | ||
358 | #define IWM_RX_TICKET_ENQUEUE 0x3 | ||
359 | |||
360 | /* Rx flags */ | ||
361 | #define IWM_RX_TICKET_PAD_SIZE_MSK 0x2 | ||
362 | #define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4 | ||
363 | #define IWM_RX_TICKET_AMSDU_MSK 0x8 | ||
364 | #define IWM_RX_TICKET_DROP_REASON_POS 4 | ||
365 | #define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << IWM_RX_TICKET_DROP_REASON_POS) | ||
366 | |||
367 | #define IWM_RX_DROP_NO_DROP 0x0 | ||
368 | #define IWM_RX_DROP_BAD_CRC 0x1 | ||
369 | /* L2P no address match */ | ||
370 | #define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2 | ||
371 | /* Multicast address not in list */ | ||
372 | #define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3 | ||
373 | /* Control frames are not sent to the driver */ | ||
374 | #define IWM_RX_DROP_CTL_FRAME 0x4 | ||
375 | /* Our frame is back */ | ||
376 | #define IWM_RX_DROP_OUR_TX 0x5 | ||
377 | /* Association class filtering */ | ||
378 | #define IWM_RX_DROP_CLASS_FILTER 0x6 | ||
379 | /* Duplicated frame */ | ||
380 | #define IWM_RX_DROP_DUPLICATE_FILTER 0x7 | ||
381 | /* Decryption error */ | ||
382 | #define IWM_RX_DROP_SEC_ERR 0x8 | ||
383 | /* Unencrypted frame while encryption is on */ | ||
384 | #define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9 | ||
385 | /* Replay check failure */ | ||
386 | #define IWM_RX_DROP_SEC_REPLAY_ERR 0xa | ||
387 | /* uCode and FW key color mismatch, check before replay */ | ||
388 | #define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb | ||
389 | #define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc | ||
390 | /* No fragmentations Db is found */ | ||
391 | #define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd | ||
392 | /* Fragmention Db has seqCtl mismatch Vs. non-1st frag */ | ||
393 | #define IWM_RX_DROP_FRAG_ERR 0xe | ||
394 | #define IWM_RX_DROP_FRAG_LOST 0xf | ||
395 | #define IWM_RX_DROP_FRAG_COMPLETE 0x10 | ||
396 | /* Should be handled by UMAC */ | ||
397 | #define IWM_RX_DROP_MANAGEMENT 0x11 | ||
398 | /* STA not found by UMAC */ | ||
399 | #define IWM_RX_DROP_NO_STATION 0x12 | ||
400 | /* NULL or QoS NULL */ | ||
401 | #define IWM_RX_DROP_NULL_DATA 0x13 | ||
402 | #define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14 | ||
403 | #define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15 | ||
404 | |||
405 | struct iwm_rx_ticket { | ||
406 | __le16 action; | ||
407 | __le16 id; | ||
408 | __le16 flags; | ||
409 | u8 payload_offset; /* includes: MAC header, pad, IV */ | ||
410 | u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */ | ||
411 | } __packed; | ||
412 | |||
413 | struct iwm_rx_mpdu_hdr { | ||
414 | __le16 len; | ||
415 | __le16 reserved; | ||
416 | } __packed; | ||
417 | |||
418 | /* UMAC SW WIFI API */ | ||
419 | |||
420 | struct iwm_dev_cmd_hdr { | ||
421 | u8 cmd; | ||
422 | u8 flags; | ||
423 | __le16 seq_num; | ||
424 | } __packed; | ||
425 | |||
426 | struct iwm_umac_fw_cmd_hdr { | ||
427 | __le32 meta_data; | ||
428 | struct iwm_dev_cmd_hdr cmd; | ||
429 | } __packed; | ||
430 | |||
431 | struct iwm_umac_wifi_out_hdr { | ||
432 | struct iwm_udma_out_wifi_hdr hw_hdr; | ||
433 | struct iwm_umac_fw_cmd_hdr sw_hdr; | ||
434 | } __packed; | ||
435 | |||
436 | struct iwm_umac_nonwifi_out_hdr { | ||
437 | struct iwm_udma_out_nonwifi_hdr hw_hdr; | ||
438 | } __packed; | ||
439 | |||
440 | struct iwm_umac_wifi_in_hdr { | ||
441 | struct iwm_udma_in_hdr hw_hdr; | ||
442 | struct iwm_umac_fw_cmd_hdr sw_hdr; | ||
443 | } __packed; | ||
444 | |||
445 | struct iwm_umac_nonwifi_in_hdr { | ||
446 | struct iwm_udma_in_hdr hw_hdr; | ||
447 | __le32 time_stamp; | ||
448 | } __packed; | ||
449 | |||
450 | #define IWM_UMAC_PAGE_SIZE 0x200 | ||
451 | |||
452 | /* Notify structures */ | ||
453 | struct iwm_fw_version { | ||
454 | u8 minor; | ||
455 | u8 major; | ||
456 | __le16 id; | ||
457 | }; | ||
458 | |||
459 | struct iwm_fw_build { | ||
460 | u8 type; | ||
461 | u8 subtype; | ||
462 | u8 platform; | ||
463 | u8 opt; | ||
464 | }; | ||
465 | |||
466 | struct iwm_fw_alive_hdr { | ||
467 | struct iwm_fw_version ver; | ||
468 | struct iwm_fw_build build; | ||
469 | __le32 os_build; | ||
470 | __le32 log_hdr_addr; | ||
471 | __le32 log_buf_addr; | ||
472 | __le32 sys_timer_addr; | ||
473 | }; | ||
474 | |||
475 | #define WAIT_NOTIF_TIMEOUT (2 * HZ) | ||
476 | #define SCAN_COMPLETE_TIMEOUT (3 * HZ) | ||
477 | |||
478 | #define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD | ||
479 | #define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE | ||
480 | |||
481 | #define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD | ||
482 | #define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE | ||
483 | |||
484 | #define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40 | ||
485 | #define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80 | ||
486 | |||
487 | #define IWM_MACS_OUT_GROUPS 6 | ||
488 | #define IWM_MACS_OUT_SGROUPS 1 | ||
489 | |||
490 | |||
491 | #define WIFI_IF_NTFY_ASSOC_START 0x80 | ||
492 | #define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81 | ||
493 | #define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82 | ||
494 | #define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83 | ||
495 | #define WIFI_IF_NTFY_SCAN_COMPLETE 0x84 | ||
496 | #define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85 | ||
497 | #define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86 | ||
498 | #define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87 | ||
499 | #define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88 | ||
500 | #define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89 | ||
501 | #define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A | ||
502 | #define WIFI_IF_NTFY_MGMT_FRAME 0x8B | ||
503 | |||
504 | /* DEBUG INDICATIONS */ | ||
505 | #define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0 | ||
506 | #define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1 | ||
507 | #define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2 | ||
508 | #define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3 | ||
509 | #define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4 | ||
510 | #define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5 | ||
511 | #define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6 | ||
512 | #define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7 | ||
513 | #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 | ||
514 | #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 | ||
515 | |||
516 | #define WIFI_IF_NTFY_MAX 0xff | ||
517 | |||
518 | /* Notification structures */ | ||
519 | struct iwm_umac_notif_wifi_if { | ||
520 | struct iwm_umac_wifi_in_hdr hdr; | ||
521 | u8 status; | ||
522 | u8 flags; | ||
523 | __le16 buf_size; | ||
524 | } __packed; | ||
525 | |||
526 | #define UMAC_ROAM_REASON_FIRST_SELECTION 0x1 | ||
527 | #define UMAC_ROAM_REASON_AP_DEAUTH 0x2 | ||
528 | #define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3 | ||
529 | #define UMAC_ROAM_REASON_RSSI 0x4 | ||
530 | #define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5 | ||
531 | #define UMAC_ROAM_REASON_IBSS_COALESCING 0x6 | ||
532 | |||
533 | struct iwm_umac_notif_assoc_start { | ||
534 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
535 | __le32 roam_reason; | ||
536 | u8 bssid[ETH_ALEN]; | ||
537 | u8 reserved[2]; | ||
538 | } __packed; | ||
539 | |||
540 | #define UMAC_ASSOC_COMPLETE_SUCCESS 0x0 | ||
541 | #define UMAC_ASSOC_COMPLETE_FAILURE 0x1 | ||
542 | |||
543 | struct iwm_umac_notif_assoc_complete { | ||
544 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
545 | __le32 status; | ||
546 | u8 bssid[ETH_ALEN]; | ||
547 | u8 band; | ||
548 | u8 channel; | ||
549 | } __packed; | ||
550 | |||
551 | #define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0 | ||
552 | #define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1 | ||
553 | #define UMAC_PROFILE_INVALID_REQUEST 0x2 | ||
554 | #define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3 | ||
555 | |||
556 | struct iwm_umac_notif_profile_invalidate { | ||
557 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
558 | __le32 reason; | ||
559 | } __packed; | ||
560 | |||
561 | #define UMAC_SCAN_RESULT_SUCCESS 0x0 | ||
562 | #define UMAC_SCAN_RESULT_ABORTED 0x1 | ||
563 | #define UMAC_SCAN_RESULT_REJECTED 0x2 | ||
564 | #define UMAC_SCAN_RESULT_FAILED 0x3 | ||
565 | |||
566 | struct iwm_umac_notif_scan_complete { | ||
567 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
568 | __le32 type; | ||
569 | __le32 result; | ||
570 | u8 seq_num; | ||
571 | } __packed; | ||
572 | |||
573 | #define UMAC_OPCODE_ADD_MODIFY 0x0 | ||
574 | #define UMAC_OPCODE_REMOVE 0x1 | ||
575 | #define UMAC_OPCODE_CLEAR_ALL 0x2 | ||
576 | |||
577 | #define UMAC_STA_FLAG_QOS 0x1 | ||
578 | |||
579 | struct iwm_umac_notif_sta_info { | ||
580 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
581 | __le32 opcode; | ||
582 | u8 mac_addr[ETH_ALEN]; | ||
583 | u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */ | ||
584 | u8 flags; | ||
585 | } __packed; | ||
586 | |||
587 | #define UMAC_BAND_2GHZ 0 | ||
588 | #define UMAC_BAND_5GHZ 1 | ||
589 | |||
590 | #define UMAC_CHANNEL_WIDTH_20MHZ 0 | ||
591 | #define UMAC_CHANNEL_WIDTH_40MHZ 1 | ||
592 | |||
593 | struct iwm_umac_notif_bss_info { | ||
594 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
595 | __le32 type; | ||
596 | __le32 timestamp; | ||
597 | __le16 table_idx; | ||
598 | __le16 frame_len; | ||
599 | u8 band; | ||
600 | u8 channel; | ||
601 | s8 rssi; | ||
602 | u8 reserved; | ||
603 | u8 frame_buf[1]; | ||
604 | } __packed; | ||
605 | |||
606 | #define IWM_BSS_REMOVE_INDEX_MSK 0x0fff | ||
607 | #define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00 | ||
608 | |||
609 | #define IWM_BSS_REMOVE_FLG_AGE 0x1000 | ||
610 | #define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000 | ||
611 | #define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000 | ||
612 | |||
613 | struct iwm_umac_notif_bss_removed { | ||
614 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
615 | __le32 count; | ||
616 | __le16 entries[0]; | ||
617 | } __packed; | ||
618 | |||
619 | struct iwm_umac_notif_mgt_frame { | ||
620 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
621 | __le16 len; | ||
622 | u8 frame[1]; | ||
623 | } __packed; | ||
624 | |||
625 | struct iwm_umac_notif_alive { | ||
626 | struct iwm_umac_wifi_in_hdr hdr; | ||
627 | __le16 status; | ||
628 | __le16 reserved1; | ||
629 | struct iwm_fw_alive_hdr alive_data; | ||
630 | __le16 reserved2; | ||
631 | __le16 page_grp_count; | ||
632 | __le32 page_grp_state[IWM_MACS_OUT_GROUPS]; | ||
633 | } __packed; | ||
634 | |||
635 | struct iwm_umac_notif_init_complete { | ||
636 | struct iwm_umac_wifi_in_hdr hdr; | ||
637 | __le16 status; | ||
638 | __le16 reserved; | ||
639 | } __packed; | ||
640 | |||
641 | /* error categories */ | ||
642 | enum { | ||
643 | UMAC_SYS_ERR_CAT_NONE = 0, | ||
644 | UMAC_SYS_ERR_CAT_BOOT, | ||
645 | UMAC_SYS_ERR_CAT_UMAC, | ||
646 | UMAC_SYS_ERR_CAT_UAXM, | ||
647 | UMAC_SYS_ERR_CAT_LMAC, | ||
648 | UMAC_SYS_ERR_CAT_MAX | ||
649 | }; | ||
650 | |||
651 | struct iwm_fw_error_hdr { | ||
652 | __le32 category; | ||
653 | __le32 status; | ||
654 | __le32 pc; | ||
655 | __le32 blink1; | ||
656 | __le32 blink2; | ||
657 | __le32 ilink1; | ||
658 | __le32 ilink2; | ||
659 | __le32 data1; | ||
660 | __le32 data2; | ||
661 | __le32 line_num; | ||
662 | __le32 umac_status; | ||
663 | __le32 lmac_status; | ||
664 | __le32 sdio_status; | ||
665 | __le32 dbm_sample_ctrl; | ||
666 | __le32 dbm_buf_base; | ||
667 | __le32 dbm_buf_end; | ||
668 | __le32 dbm_buf_write_ptr; | ||
669 | __le32 dbm_buf_cycle_cnt; | ||
670 | } __packed; | ||
671 | |||
672 | struct iwm_umac_notif_error { | ||
673 | struct iwm_umac_wifi_in_hdr hdr; | ||
674 | struct iwm_fw_error_hdr err; | ||
675 | } __packed; | ||
676 | |||
677 | #define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0 | ||
678 | #define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff | ||
679 | #define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8 | ||
680 | #define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff | ||
681 | #define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0 | ||
682 | #define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff | ||
683 | #define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24 | ||
684 | #define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf | ||
685 | |||
686 | struct iwm_umac_notif_page_dealloc { | ||
687 | struct iwm_umac_wifi_in_hdr hdr; | ||
688 | __le32 changes; | ||
689 | __le32 grp_info[IWM_MACS_OUT_GROUPS]; | ||
690 | } __packed; | ||
691 | |||
692 | struct iwm_umac_notif_wifi_status { | ||
693 | struct iwm_umac_wifi_in_hdr hdr; | ||
694 | __le16 status; | ||
695 | __le16 reserved; | ||
696 | } __packed; | ||
697 | |||
698 | struct iwm_umac_notif_rx_ticket { | ||
699 | struct iwm_umac_wifi_in_hdr hdr; | ||
700 | u8 num_tickets; | ||
701 | u8 reserved[3]; | ||
702 | struct iwm_rx_ticket tickets[1]; | ||
703 | } __packed; | ||
704 | |||
705 | /* Tx/Rx rates window (number of max of last update window per second) */ | ||
706 | #define UMAC_NTF_RATE_SAMPLE_NR 4 | ||
707 | |||
708 | /* Max numbers of bits required to go through all antennae in bitmasks */ | ||
709 | #define UMAC_PHY_NUM_CHAINS 3 | ||
710 | |||
711 | #define IWM_UMAC_MGMT_TID 8 | ||
712 | #define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */ | ||
713 | |||
714 | struct iwm_umac_notif_stats { | ||
715 | struct iwm_umac_wifi_in_hdr hdr; | ||
716 | __le32 flags; | ||
717 | __le32 timestamp; | ||
718 | __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */ | ||
719 | __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; | ||
720 | __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; | ||
721 | __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; | ||
722 | s32 rssi_dbm; | ||
723 | s32 noise_dbm; | ||
724 | __le32 supp_rates; | ||
725 | __le32 supp_ht_rates; | ||
726 | __le32 missed_beacons; | ||
727 | __le32 rx_beacons; | ||
728 | __le32 rx_dir_pkts; | ||
729 | __le32 rx_nondir_pkts; | ||
730 | __le32 rx_multicast; | ||
731 | __le32 rx_errors; | ||
732 | __le32 rx_drop_other_bssid; | ||
733 | __le32 rx_drop_decode; | ||
734 | __le32 rx_drop_reassembly; | ||
735 | __le32 rx_drop_bad_len; | ||
736 | __le32 rx_drop_overflow; | ||
737 | __le32 rx_drop_crc; | ||
738 | __le32 rx_drop_missed; | ||
739 | __le32 tx_dir_pkts; | ||
740 | __le32 tx_nondir_pkts; | ||
741 | __le32 tx_failure; | ||
742 | __le32 tx_errors; | ||
743 | __le32 tx_drop_max_retry; | ||
744 | __le32 tx_err_abort; | ||
745 | __le32 tx_err_carrier; | ||
746 | __le32 rx_bytes; | ||
747 | __le32 tx_bytes; | ||
748 | __le32 tx_power; | ||
749 | __le32 tx_max_power; | ||
750 | __le32 roam_threshold; | ||
751 | __le32 ap_assoc_nr; | ||
752 | __le32 scan_full; | ||
753 | __le32 scan_abort; | ||
754 | __le32 ap_nr; | ||
755 | __le32 roam_nr; | ||
756 | __le32 roam_missed_beacons; | ||
757 | __le32 roam_rssi; | ||
758 | __le32 roam_unassoc; | ||
759 | __le32 roam_deauth; | ||
760 | __le32 roam_ap_loadblance; | ||
761 | } __packed; | ||
762 | |||
763 | #define UMAC_STOP_TX_FLAG 0x1 | ||
764 | #define UMAC_RESUME_TX_FLAG 0x2 | ||
765 | |||
766 | #define LAST_SEQ_NUM_INVALID 0xFFFF | ||
767 | |||
768 | struct iwm_umac_notif_stop_resume_tx { | ||
769 | struct iwm_umac_wifi_in_hdr hdr; | ||
770 | u8 flags; /* UMAC_*_TX_FLAG_* */ | ||
771 | u8 sta_id; | ||
772 | __le16 stop_resume_tid_msk; /* tid bitmask */ | ||
773 | } __packed; | ||
774 | |||
775 | #define UMAC_MAX_NUM_PMKIDS 4 | ||
776 | |||
777 | /* WiFi interface wrapper header */ | ||
778 | struct iwm_umac_wifi_if { | ||
779 | u8 oid; | ||
780 | u8 flags; | ||
781 | __le16 buf_size; | ||
782 | } __packed; | ||
783 | |||
784 | #define IWM_SEQ_NUM_HOST_MSK 0x0000 | ||
785 | #define IWM_SEQ_NUM_UMAC_MSK 0x4000 | ||
786 | #define IWM_SEQ_NUM_LMAC_MSK 0x8000 | ||
787 | #define IWM_SEQ_NUM_MSK 0xC000 | ||
788 | |||
789 | #endif | ||
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 2e2dbfa2ee50..96726f79a1dd 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -68,7 +68,6 @@ | |||
68 | #define CMD_802_11_BEACON_STOP 0x0049 | 68 | #define CMD_802_11_BEACON_STOP 0x0049 |
69 | #define CMD_802_11_MAC_ADDRESS 0x004d | 69 | #define CMD_802_11_MAC_ADDRESS 0x004d |
70 | #define CMD_802_11_LED_GPIO_CTRL 0x004e | 70 | #define CMD_802_11_LED_GPIO_CTRL 0x004e |
71 | #define CMD_802_11_EEPROM_ACCESS 0x0059 | ||
72 | #define CMD_802_11_BAND_CONFIG 0x0058 | 71 | #define CMD_802_11_BAND_CONFIG 0x0058 |
73 | #define CMD_GSPI_BUS_CONFIG 0x005a | 72 | #define CMD_GSPI_BUS_CONFIG 0x005a |
74 | #define CMD_802_11D_DOMAIN_INFO 0x005b | 73 | #define CMD_802_11D_DOMAIN_INFO 0x005b |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index f578d0b2172d..200bcc0ead98 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -292,7 +292,7 @@ struct mac80211_hwsim_data { | |||
292 | struct list_head list; | 292 | struct list_head list; |
293 | struct ieee80211_hw *hw; | 293 | struct ieee80211_hw *hw; |
294 | struct device *dev; | 294 | struct device *dev; |
295 | struct ieee80211_supported_band bands[2]; | 295 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; |
296 | struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; | 296 | struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; |
297 | struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; | 297 | struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; |
298 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; | 298 | struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; |
@@ -1082,6 +1082,8 @@ enum hwsim_testmode_attr { | |||
1082 | enum hwsim_testmode_cmd { | 1082 | enum hwsim_testmode_cmd { |
1083 | HWSIM_TM_CMD_SET_PS = 0, | 1083 | HWSIM_TM_CMD_SET_PS = 0, |
1084 | HWSIM_TM_CMD_GET_PS = 1, | 1084 | HWSIM_TM_CMD_GET_PS = 1, |
1085 | HWSIM_TM_CMD_STOP_QUEUES = 2, | ||
1086 | HWSIM_TM_CMD_WAKE_QUEUES = 3, | ||
1085 | }; | 1087 | }; |
1086 | 1088 | ||
1087 | static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { | 1089 | static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { |
@@ -1121,6 +1123,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, | |||
1121 | if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) | 1123 | if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) |
1122 | goto nla_put_failure; | 1124 | goto nla_put_failure; |
1123 | return cfg80211_testmode_reply(skb); | 1125 | return cfg80211_testmode_reply(skb); |
1126 | case HWSIM_TM_CMD_STOP_QUEUES: | ||
1127 | ieee80211_stop_queues(hw); | ||
1128 | return 0; | ||
1129 | case HWSIM_TM_CMD_WAKE_QUEUES: | ||
1130 | ieee80211_wake_queues(hw); | ||
1131 | return 0; | ||
1124 | default: | 1132 | default: |
1125 | return -EOPNOTSUPP; | 1133 | return -EOPNOTSUPP; |
1126 | } | 1134 | } |
@@ -1855,7 +1863,7 @@ static int __init init_mac80211_hwsim(void) | |||
1855 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; | 1863 | sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; |
1856 | break; | 1864 | break; |
1857 | default: | 1865 | default: |
1858 | break; | 1866 | continue; |
1859 | } | 1867 | } |
1860 | 1868 | ||
1861 | sband->ht_cap.ht_supported = true; | 1869 | sband->ht_cap.ht_supported = true; |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 3af88b8cfcb7..c7a177c62625 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -914,6 +914,69 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, | |||
914 | return 0; | 914 | return 0; |
915 | } | 915 | } |
916 | 916 | ||
917 | /* cfg80211 operation handler for change_beacon. | ||
918 | * Function retrieves and sets modified management IEs to FW. | ||
919 | */ | ||
920 | static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, | ||
921 | struct net_device *dev, | ||
922 | struct cfg80211_beacon_data *data) | ||
923 | { | ||
924 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
925 | |||
926 | if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { | ||
927 | wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__); | ||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | if (!priv->bss_started) { | ||
932 | wiphy_err(wiphy, "%s: bss not started\n", __func__); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | |||
936 | if (mwifiex_set_mgmt_ies(priv, data)) { | ||
937 | wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__); | ||
938 | return -EFAULT; | ||
939 | } | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int | ||
945 | mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) | ||
946 | { | ||
947 | struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); | ||
948 | struct mwifiex_private *priv = mwifiex_get_priv(adapter, | ||
949 | MWIFIEX_BSS_ROLE_ANY); | ||
950 | struct mwifiex_ds_ant_cfg ant_cfg; | ||
951 | |||
952 | if (!tx_ant || !rx_ant) | ||
953 | return -EOPNOTSUPP; | ||
954 | |||
955 | if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) { | ||
956 | /* Not a MIMO chip. User should provide specific antenna number | ||
957 | * for Tx/Rx path or enable all antennas for diversity | ||
958 | */ | ||
959 | if (tx_ant != rx_ant) | ||
960 | return -EOPNOTSUPP; | ||
961 | |||
962 | if ((tx_ant & (tx_ant - 1)) && | ||
963 | (tx_ant != BIT(adapter->number_of_antenna) - 1)) | ||
964 | return -EOPNOTSUPP; | ||
965 | |||
966 | if ((tx_ant == BIT(adapter->number_of_antenna) - 1) && | ||
967 | (priv->adapter->number_of_antenna > 1)) { | ||
968 | tx_ant = RF_ANTENNA_AUTO; | ||
969 | rx_ant = RF_ANTENNA_AUTO; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | ant_cfg.tx_ant = tx_ant; | ||
974 | ant_cfg.rx_ant = rx_ant; | ||
975 | |||
976 | return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA, | ||
977 | HostCmd_ACT_GEN_SET, 0, &ant_cfg); | ||
978 | } | ||
979 | |||
917 | /* cfg80211 operation handler for stop ap. | 980 | /* cfg80211 operation handler for stop ap. |
918 | * Function stops BSS running at uAP interface. | 981 | * Function stops BSS running at uAP interface. |
919 | */ | 982 | */ |
@@ -947,7 +1010,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, | |||
947 | 1010 | ||
948 | if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) | 1011 | if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) |
949 | return -1; | 1012 | return -1; |
950 | if (mwifiex_set_mgmt_ies(priv, params)) | 1013 | if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) |
951 | return -1; | 1014 | return -1; |
952 | 1015 | ||
953 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); | 1016 | bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); |
@@ -1697,7 +1760,9 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { | |||
1697 | .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, | 1760 | .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, |
1698 | .start_ap = mwifiex_cfg80211_start_ap, | 1761 | .start_ap = mwifiex_cfg80211_start_ap, |
1699 | .stop_ap = mwifiex_cfg80211_stop_ap, | 1762 | .stop_ap = mwifiex_cfg80211_stop_ap, |
1763 | .change_beacon = mwifiex_cfg80211_change_beacon, | ||
1700 | .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, | 1764 | .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, |
1765 | .set_antenna = mwifiex_cfg80211_set_antenna, | ||
1701 | }; | 1766 | }; |
1702 | 1767 | ||
1703 | /* | 1768 | /* |
@@ -1744,7 +1809,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) | |||
1744 | 1809 | ||
1745 | memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); | 1810 | memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); |
1746 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 1811 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
1747 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; | 1812 | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | |
1813 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
1814 | |||
1815 | wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
1816 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; | ||
1817 | |||
1818 | wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; | ||
1819 | wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; | ||
1748 | 1820 | ||
1749 | /* Reserve space for mwifiex specific private data for BSS */ | 1821 | /* Reserve space for mwifiex specific private data for BSS */ |
1750 | wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); | 1822 | wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index ffb6cdfdb797..14e985d01dee 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -227,6 +227,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { | |||
227 | #define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad | 227 | #define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad |
228 | #define HostCmd_CMD_802_11_RF_CHANNEL 0x001d | 228 | #define HostCmd_CMD_802_11_RF_CHANNEL 0x001d |
229 | #define HostCmd_CMD_RF_TX_PWR 0x001e | 229 | #define HostCmd_CMD_RF_TX_PWR 0x001e |
230 | #define HostCmd_CMD_RF_ANTENNA 0x0020 | ||
230 | #define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 | 231 | #define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 |
231 | #define HostCmd_CMD_MAC_CONTROL 0x0028 | 232 | #define HostCmd_CMD_MAC_CONTROL 0x0028 |
232 | #define HostCmd_CMD_802_11_AD_HOC_START 0x002b | 233 | #define HostCmd_CMD_802_11_AD_HOC_START 0x002b |
@@ -322,6 +323,12 @@ enum ENH_PS_MODES { | |||
322 | 323 | ||
323 | #define HostCmd_BSS_TYPE_MASK 0xf000 | 324 | #define HostCmd_BSS_TYPE_MASK 0xf000 |
324 | 325 | ||
326 | #define HostCmd_ACT_SET_RX 0x0001 | ||
327 | #define HostCmd_ACT_SET_TX 0x0002 | ||
328 | #define HostCmd_ACT_SET_BOTH 0x0003 | ||
329 | |||
330 | #define RF_ANTENNA_AUTO 0xFFFF | ||
331 | |||
325 | #define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ | 332 | #define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ |
326 | (((seq) & 0x00ff) | \ | 333 | (((seq) & 0x00ff) | \ |
327 | (((num) & 0x000f) << 8)) | \ | 334 | (((num) & 0x000f) << 8)) | \ |
@@ -884,6 +891,18 @@ struct host_cmd_ds_rf_tx_pwr { | |||
884 | u8 min_power; | 891 | u8 min_power; |
885 | } __packed; | 892 | } __packed; |
886 | 893 | ||
894 | struct host_cmd_ds_rf_ant_mimo { | ||
895 | __le16 action_tx; | ||
896 | __le16 tx_ant_mode; | ||
897 | __le16 action_rx; | ||
898 | __le16 rx_ant_mode; | ||
899 | }; | ||
900 | |||
901 | struct host_cmd_ds_rf_ant_siso { | ||
902 | __le16 action; | ||
903 | __le16 ant_mode; | ||
904 | }; | ||
905 | |||
887 | struct mwifiex_bcn_param { | 906 | struct mwifiex_bcn_param { |
888 | u8 bssid[ETH_ALEN]; | 907 | u8 bssid[ETH_ALEN]; |
889 | u8 rssi; | 908 | u8 rssi; |
@@ -1370,6 +1389,8 @@ struct host_cmd_ds_command { | |||
1370 | struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; | 1389 | struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; |
1371 | struct host_cmd_ds_txpwr_cfg txp_cfg; | 1390 | struct host_cmd_ds_txpwr_cfg txp_cfg; |
1372 | struct host_cmd_ds_rf_tx_pwr txp; | 1391 | struct host_cmd_ds_rf_tx_pwr txp; |
1392 | struct host_cmd_ds_rf_ant_mimo ant_mimo; | ||
1393 | struct host_cmd_ds_rf_ant_siso ant_siso; | ||
1373 | struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; | 1394 | struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; |
1374 | struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; | 1395 | struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; |
1375 | struct host_cmd_ds_802_11_scan scan; | 1396 | struct host_cmd_ds_802_11_scan scan; |
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 8374e33f195a..1d8dd003e396 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c | |||
@@ -51,8 +51,7 @@ mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask, | |||
51 | 51 | ||
52 | for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) { | 52 | for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) { |
53 | mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask); | 53 | mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask); |
54 | len = le16_to_cpu(priv->mgmt_ie[i].ie_length) + | 54 | len = le16_to_cpu(ie->ie_length); |
55 | le16_to_cpu(ie->ie_length); | ||
56 | 55 | ||
57 | if (mask == MWIFIEX_AUTO_IDX_MASK) | 56 | if (mask == MWIFIEX_AUTO_IDX_MASK) |
58 | continue; | 57 | continue; |
@@ -108,10 +107,8 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, | |||
108 | return -1; | 107 | return -1; |
109 | 108 | ||
110 | tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; | 109 | tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; |
111 | tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length); | ||
112 | memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); | 110 | memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); |
113 | le16_add_cpu(&priv->mgmt_ie[index].ie_length, | 111 | priv->mgmt_ie[index].ie_length = ie->ie_length; |
114 | le16_to_cpu(ie->ie_length)); | ||
115 | priv->mgmt_ie[index].ie_index = cpu_to_le16(index); | 112 | priv->mgmt_ie[index].ie_index = cpu_to_le16(index); |
116 | priv->mgmt_ie[index].mgmt_subtype_mask = | 113 | priv->mgmt_ie[index].mgmt_subtype_mask = |
117 | cpu_to_le16(mask); | 114 | cpu_to_le16(mask); |
@@ -217,34 +214,107 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, | |||
217 | return ret; | 214 | return ret; |
218 | } | 215 | } |
219 | 216 | ||
220 | /* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs, | 217 | /* This function checks if WPS IE is present in passed buffer and copies it to |
218 | * mwifiex_ie structure. | ||
219 | * Function takes pointer to struct mwifiex_ie pointer as argument. | ||
220 | * If WPS IE is present memory is allocated for mwifiex_ie pointer and filled | ||
221 | * in with WPS IE. Caller should take care of freeing this memory. | ||
222 | */ | ||
223 | static int mwifiex_update_wps_ie(const u8 *ies, int ies_len, | ||
224 | struct mwifiex_ie **ie_ptr, u16 mask) | ||
225 | { | ||
226 | struct ieee_types_header *wps_ie; | ||
227 | struct mwifiex_ie *ie = NULL; | ||
228 | const u8 *vendor_ie; | ||
229 | |||
230 | vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, | ||
231 | WLAN_OUI_TYPE_MICROSOFT_WPS, | ||
232 | ies, ies_len); | ||
233 | if (vendor_ie) { | ||
234 | ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | ||
235 | if (!ie) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | wps_ie = (struct ieee_types_header *)vendor_ie; | ||
239 | memcpy(ie->ie_buffer, wps_ie, wps_ie->len + 2); | ||
240 | ie->ie_length = cpu_to_le16(wps_ie->len + 2); | ||
241 | ie->mgmt_subtype_mask = cpu_to_le16(mask); | ||
242 | ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK); | ||
243 | } | ||
244 | |||
245 | *ie_ptr = ie; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* This function parses beacon IEs, probe response IEs, association response IEs | ||
250 | * from cfg80211_ap_settings->beacon and sets these IE to FW. | ||
251 | */ | ||
252 | static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv, | ||
253 | struct cfg80211_beacon_data *data) | ||
254 | { | ||
255 | struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL; | ||
256 | u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK; | ||
257 | u16 ar_idx = MWIFIEX_AUTO_IDX_MASK; | ||
258 | int ret = 0; | ||
259 | |||
260 | if (data->beacon_ies && data->beacon_ies_len) | ||
261 | mwifiex_update_wps_ie(data->beacon_ies, data->beacon_ies_len, | ||
262 | &beacon_ie, MGMT_MASK_BEACON); | ||
263 | |||
264 | if (data->proberesp_ies && data->proberesp_ies_len) | ||
265 | mwifiex_update_wps_ie(data->proberesp_ies, | ||
266 | data->proberesp_ies_len, &pr_ie, | ||
267 | MGMT_MASK_PROBE_RESP); | ||
268 | |||
269 | if (data->assocresp_ies && data->assocresp_ies_len) | ||
270 | mwifiex_update_wps_ie(data->assocresp_ies, | ||
271 | data->assocresp_ies_len, &ar_ie, | ||
272 | MGMT_MASK_ASSOC_RESP | | ||
273 | MGMT_MASK_REASSOC_RESP); | ||
274 | |||
275 | if (beacon_ie || pr_ie || ar_ie) { | ||
276 | ret = mwifiex_update_uap_custom_ie(priv, beacon_ie, | ||
277 | &beacon_idx, pr_ie, | ||
278 | &pr_idx, ar_ie, &ar_idx); | ||
279 | if (ret) | ||
280 | goto done; | ||
281 | } | ||
282 | |||
283 | priv->beacon_idx = beacon_idx; | ||
284 | priv->proberesp_idx = pr_idx; | ||
285 | priv->assocresp_idx = ar_idx; | ||
286 | |||
287 | done: | ||
288 | kfree(beacon_ie); | ||
289 | kfree(pr_ie); | ||
290 | kfree(ar_ie); | ||
291 | |||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | /* This function parses different IEs-tail IEs, beacon IEs, probe response IEs, | ||
221 | * association response IEs from cfg80211_ap_settings function and sets these IE | 296 | * association response IEs from cfg80211_ap_settings function and sets these IE |
222 | * to FW. | 297 | * to FW. |
223 | */ | 298 | */ |
224 | int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, | 299 | int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, |
225 | struct cfg80211_ap_settings *params) | 300 | struct cfg80211_beacon_data *info) |
226 | { | 301 | { |
227 | struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; | 302 | struct mwifiex_ie *gen_ie; |
228 | struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL; | 303 | struct ieee_types_header *rsn_ie, *wpa_ie = NULL; |
229 | struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL; | 304 | u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; |
230 | u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK; | ||
231 | u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK; | ||
232 | u16 mask, ie_len = 0; | ||
233 | const u8 *vendor_ie; | 305 | const u8 *vendor_ie; |
234 | int ret = 0; | ||
235 | 306 | ||
236 | if (params->beacon.tail && params->beacon.tail_len) { | 307 | if (info->tail && info->tail_len) { |
237 | gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | 308 | gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); |
238 | if (!gen_ie) | 309 | if (!gen_ie) |
239 | return -ENOMEM; | 310 | return -ENOMEM; |
240 | gen_ie->ie_index = cpu_to_le16(rsn_idx); | 311 | gen_ie->ie_index = cpu_to_le16(rsn_idx); |
241 | mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | | 312 | gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | |
242 | MGMT_MASK_ASSOC_RESP; | 313 | MGMT_MASK_PROBE_RESP | |
243 | gen_ie->mgmt_subtype_mask = cpu_to_le16(mask); | 314 | MGMT_MASK_ASSOC_RESP); |
244 | 315 | ||
245 | rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, | 316 | rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, |
246 | params->beacon.tail, | 317 | info->tail, info->tail_len); |
247 | params->beacon.tail_len); | ||
248 | if (rsn_ie) { | 318 | if (rsn_ie) { |
249 | memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2); | 319 | memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2); |
250 | ie_len = rsn_ie->len + 2; | 320 | ie_len = rsn_ie->len + 2; |
@@ -253,8 +323,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, | |||
253 | 323 | ||
254 | vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, | 324 | vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, |
255 | WLAN_OUI_TYPE_MICROSOFT_WPA, | 325 | WLAN_OUI_TYPE_MICROSOFT_WPA, |
256 | params->beacon.tail, | 326 | info->tail, |
257 | params->beacon.tail_len); | 327 | info->tail_len); |
258 | if (vendor_ie) { | 328 | if (vendor_ie) { |
259 | wpa_ie = (struct ieee_types_header *)vendor_ie; | 329 | wpa_ie = (struct ieee_types_header *)vendor_ie; |
260 | memcpy(gen_ie->ie_buffer + ie_len, | 330 | memcpy(gen_ie->ie_buffer + ie_len, |
@@ -267,79 +337,16 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, | |||
267 | if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, | 337 | if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, |
268 | NULL, NULL, | 338 | NULL, NULL, |
269 | NULL, NULL)) { | 339 | NULL, NULL)) { |
270 | ret = -1; | 340 | kfree(gen_ie); |
271 | goto done; | 341 | return -1; |
272 | } | 342 | } |
273 | |||
274 | priv->rsn_idx = rsn_idx; | 343 | priv->rsn_idx = rsn_idx; |
275 | } | 344 | } |
276 | } | ||
277 | |||
278 | if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) { | ||
279 | beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | ||
280 | if (!beacon_ie) { | ||
281 | ret = -ENOMEM; | ||
282 | goto done; | ||
283 | } | ||
284 | |||
285 | beacon_ie->ie_index = cpu_to_le16(beacon_idx); | ||
286 | beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON); | ||
287 | beacon_ie->ie_length = | ||
288 | cpu_to_le16(params->beacon.beacon_ies_len); | ||
289 | memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies, | ||
290 | params->beacon.beacon_ies_len); | ||
291 | } | ||
292 | |||
293 | if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) { | ||
294 | pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | ||
295 | if (!pr_ie) { | ||
296 | ret = -ENOMEM; | ||
297 | goto done; | ||
298 | } | ||
299 | |||
300 | pr_ie->ie_index = cpu_to_le16(pr_idx); | ||
301 | pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP); | ||
302 | pr_ie->ie_length = | ||
303 | cpu_to_le16(params->beacon.proberesp_ies_len); | ||
304 | memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies, | ||
305 | params->beacon.proberesp_ies_len); | ||
306 | } | ||
307 | |||
308 | if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) { | ||
309 | ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); | ||
310 | if (!ar_ie) { | ||
311 | ret = -ENOMEM; | ||
312 | goto done; | ||
313 | } | ||
314 | 345 | ||
315 | ar_ie->ie_index = cpu_to_le16(ar_idx); | 346 | kfree(gen_ie); |
316 | mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP; | ||
317 | ar_ie->mgmt_subtype_mask = cpu_to_le16(mask); | ||
318 | ar_ie->ie_length = | ||
319 | cpu_to_le16(params->beacon.assocresp_ies_len); | ||
320 | memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies, | ||
321 | params->beacon.assocresp_ies_len); | ||
322 | } | ||
323 | |||
324 | if (beacon_ie || pr_ie || ar_ie) { | ||
325 | ret = mwifiex_update_uap_custom_ie(priv, beacon_ie, | ||
326 | &beacon_idx, pr_ie, | ||
327 | &pr_idx, ar_ie, &ar_idx); | ||
328 | if (ret) | ||
329 | goto done; | ||
330 | } | 347 | } |
331 | 348 | ||
332 | priv->beacon_idx = beacon_idx; | 349 | return mwifiex_set_mgmt_beacon_data_ies(priv, info); |
333 | priv->proberesp_idx = pr_idx; | ||
334 | priv->assocresp_idx = ar_idx; | ||
335 | |||
336 | done: | ||
337 | kfree(beacon_ie); | ||
338 | kfree(pr_ie); | ||
339 | kfree(ar_ie); | ||
340 | kfree(gen_ie); | ||
341 | |||
342 | return ret; | ||
343 | } | 350 | } |
344 | 351 | ||
345 | /* This function removes management IE set */ | 352 | /* This function removes management IE set */ |
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 9f088fb88cb7..e121294cc1ac 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h | |||
@@ -277,6 +277,11 @@ struct mwifiex_ds_11n_amsdu_aggr_ctrl { | |||
277 | u16 curr_buf_size; | 277 | u16 curr_buf_size; |
278 | }; | 278 | }; |
279 | 279 | ||
280 | struct mwifiex_ds_ant_cfg { | ||
281 | u32 tx_ant; | ||
282 | u32 rx_ant; | ||
283 | }; | ||
284 | |||
280 | #define MWIFIEX_NUM_OF_CMD_BUFFER 20 | 285 | #define MWIFIEX_NUM_OF_CMD_BUFFER 20 |
281 | #define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 | 286 | #define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 |
282 | 287 | ||
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 7cd95cc99a85..9e636535cbf6 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -1013,7 +1013,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); | |||
1013 | void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config); | 1013 | void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config); |
1014 | 1014 | ||
1015 | int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, | 1015 | int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, |
1016 | struct cfg80211_ap_settings *params); | 1016 | struct cfg80211_beacon_data *data); |
1017 | int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); | 1017 | int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); |
1018 | u8 *mwifiex_11d_code_2_region(u8 code); | 1018 | u8 *mwifiex_11d_code_2_region(u8 code); |
1019 | 1019 | ||
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index b9cd9ed48c45..225d4c776177 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c | |||
@@ -277,6 +277,39 @@ static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv, | |||
277 | } | 277 | } |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * This function prepares command to set rf antenna. | ||
281 | */ | ||
282 | static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv, | ||
283 | struct host_cmd_ds_command *cmd, | ||
284 | u16 cmd_action, | ||
285 | struct mwifiex_ds_ant_cfg *ant_cfg) | ||
286 | { | ||
287 | struct host_cmd_ds_rf_ant_mimo *ant_mimo = &cmd->params.ant_mimo; | ||
288 | struct host_cmd_ds_rf_ant_siso *ant_siso = &cmd->params.ant_siso; | ||
289 | |||
290 | cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA); | ||
291 | |||
292 | if (cmd_action != HostCmd_ACT_GEN_SET) | ||
293 | return 0; | ||
294 | |||
295 | if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { | ||
296 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_mimo) + | ||
297 | S_DS_GEN); | ||
298 | ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX); | ||
299 | ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); | ||
300 | ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX); | ||
301 | ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->rx_ant); | ||
302 | } else { | ||
303 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_siso) + | ||
304 | S_DS_GEN); | ||
305 | ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH); | ||
306 | ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); | ||
307 | } | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /* | ||
280 | * This function prepares command to set Host Sleep configuration. | 313 | * This function prepares command to set Host Sleep configuration. |
281 | * | 314 | * |
282 | * Preparation includes - | 315 | * Preparation includes - |
@@ -1070,6 +1103,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | |||
1070 | ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action, | 1103 | ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action, |
1071 | data_buf); | 1104 | data_buf); |
1072 | break; | 1105 | break; |
1106 | case HostCmd_CMD_RF_ANTENNA: | ||
1107 | ret = mwifiex_cmd_rf_antenna(priv, cmd_ptr, cmd_action, | ||
1108 | data_buf); | ||
1109 | break; | ||
1073 | case HostCmd_CMD_802_11_PS_MODE_ENH: | 1110 | case HostCmd_CMD_802_11_PS_MODE_ENH: |
1074 | ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, | 1111 | ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, |
1075 | (uint16_t)cmd_oid, data_buf); | 1112 | (uint16_t)cmd_oid, data_buf); |
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 78fc352c85c4..97715dfbdf58 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c | |||
@@ -475,6 +475,33 @@ static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv, | |||
475 | } | 475 | } |
476 | 476 | ||
477 | /* | 477 | /* |
478 | * This function handles the command response of set rf antenna | ||
479 | */ | ||
480 | static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, | ||
481 | struct host_cmd_ds_command *resp) | ||
482 | { | ||
483 | struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo; | ||
484 | struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; | ||
485 | struct mwifiex_adapter *adapter = priv->adapter; | ||
486 | |||
487 | if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) | ||
488 | dev_dbg(adapter->dev, | ||
489 | "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x" | ||
490 | " Rx action = 0x%x, Rx Mode = 0x%04x\n", | ||
491 | le16_to_cpu(ant_mimo->action_tx), | ||
492 | le16_to_cpu(ant_mimo->tx_ant_mode), | ||
493 | le16_to_cpu(ant_mimo->action_rx), | ||
494 | le16_to_cpu(ant_mimo->rx_ant_mode)); | ||
495 | else | ||
496 | dev_dbg(adapter->dev, | ||
497 | "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", | ||
498 | le16_to_cpu(ant_siso->action), | ||
499 | le16_to_cpu(ant_siso->ant_mode)); | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /* | ||
478 | * This function handles the command response of set/get MAC address. | 505 | * This function handles the command response of set/get MAC address. |
479 | * | 506 | * |
480 | * Handling includes saving the MAC address in driver. | 507 | * Handling includes saving the MAC address in driver. |
@@ -868,6 +895,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, | |||
868 | case HostCmd_CMD_RF_TX_PWR: | 895 | case HostCmd_CMD_RF_TX_PWR: |
869 | ret = mwifiex_ret_rf_tx_power(priv, resp); | 896 | ret = mwifiex_ret_rf_tx_power(priv, resp); |
870 | break; | 897 | break; |
898 | case HostCmd_CMD_RF_ANTENNA: | ||
899 | ret = mwifiex_ret_rf_antenna(priv, resp); | ||
900 | break; | ||
871 | case HostCmd_CMD_802_11_PS_MODE_ENH: | 901 | case HostCmd_CMD_802_11_PS_MODE_ENH: |
872 | ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); | 902 | ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); |
873 | break; | 903 | break; |
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 82a1cac920bd..f38786e02623 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c | |||
@@ -422,11 +422,11 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) | |||
422 | * Clear manually, ieee80211_tx_info_clear_status would | 422 | * Clear manually, ieee80211_tx_info_clear_status would |
423 | * clear the counts too and we need them. | 423 | * clear the counts too and we need them. |
424 | */ | 424 | */ |
425 | memset(&info->status.ampdu_ack_len, 0, | 425 | memset(&info->status.ack_signal, 0, |
426 | sizeof(struct ieee80211_tx_info) - | 426 | sizeof(struct ieee80211_tx_info) - |
427 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); | 427 | offsetof(struct ieee80211_tx_info, status.ack_signal)); |
428 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, | 428 | BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, |
429 | status.ampdu_ack_len) != 23); | 429 | status.ack_signal) != 20); |
430 | 430 | ||
431 | if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) | 431 | if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) |
432 | pad = entry_data->align[0]; | 432 | pad = entry_data->align[0]; |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 068276ee8aff..e76f03c9b468 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -1940,10 +1940,8 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, | |||
1940 | rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); | 1940 | rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); |
1941 | } | 1941 | } |
1942 | 1942 | ||
1943 | #define RT3290_POWER_BOUND 0x27 | 1943 | #define POWER_BOUND 0x27 |
1944 | #define RT3290_FREQ_OFFSET_BOUND 0x5f | 1944 | #define FREQ_OFFSET_BOUND 0x5f |
1945 | #define RT5390_POWER_BOUND 0x27 | ||
1946 | #define RT5390_FREQ_OFFSET_BOUND 0x5f | ||
1947 | 1945 | ||
1948 | static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, | 1946 | static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, |
1949 | struct ieee80211_conf *conf, | 1947 | struct ieee80211_conf *conf, |
@@ -1959,16 +1957,15 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, | |||
1959 | rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); | 1957 | rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
1960 | 1958 | ||
1961 | rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); | 1959 | rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); |
1962 | if (info->default_power1 > RT3290_POWER_BOUND) | 1960 | if (info->default_power1 > POWER_BOUND) |
1963 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT3290_POWER_BOUND); | 1961 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); |
1964 | else | 1962 | else |
1965 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); | 1963 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); |
1966 | rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); | 1964 | rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); |
1967 | 1965 | ||
1968 | rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); | 1966 | rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); |
1969 | if (rt2x00dev->freq_offset > RT3290_FREQ_OFFSET_BOUND) | 1967 | if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND) |
1970 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, | 1968 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND); |
1971 | RT3290_FREQ_OFFSET_BOUND); | ||
1972 | else | 1969 | else |
1973 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); | 1970 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); |
1974 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); | 1971 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); |
@@ -2002,17 +1999,16 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, | |||
2002 | rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); | 1999 | rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); |
2003 | 2000 | ||
2004 | rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); | 2001 | rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); |
2005 | if (info->default_power1 > RT5390_POWER_BOUND) | 2002 | if (info->default_power1 > POWER_BOUND) |
2006 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT5390_POWER_BOUND); | 2003 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); |
2007 | else | 2004 | else |
2008 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); | 2005 | rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); |
2009 | rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); | 2006 | rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); |
2010 | 2007 | ||
2011 | if (rt2x00_rt(rt2x00dev, RT5392)) { | 2008 | if (rt2x00_rt(rt2x00dev, RT5392)) { |
2012 | rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); | 2009 | rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); |
2013 | if (info->default_power1 > RT5390_POWER_BOUND) | 2010 | if (info->default_power1 > POWER_BOUND) |
2014 | rt2x00_set_field8(&rfcsr, RFCSR50_TX, | 2011 | rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND); |
2015 | RT5390_POWER_BOUND); | ||
2016 | else | 2012 | else |
2017 | rt2x00_set_field8(&rfcsr, RFCSR50_TX, | 2013 | rt2x00_set_field8(&rfcsr, RFCSR50_TX, |
2018 | info->default_power2); | 2014 | info->default_power2); |
@@ -2031,9 +2027,8 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, | |||
2031 | rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); | 2027 | rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); |
2032 | 2028 | ||
2033 | rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); | 2029 | rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); |
2034 | if (rt2x00dev->freq_offset > RT5390_FREQ_OFFSET_BOUND) | 2030 | if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND) |
2035 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, | 2031 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND); |
2036 | RT5390_FREQ_OFFSET_BOUND); | ||
2037 | else | 2032 | else |
2038 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); | 2033 | rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); |
2039 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); | 2034 | rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index dd436125fe3d..235376e9cb04 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -986,7 +986,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) | |||
986 | int i, count; | 986 | int i, count; |
987 | 987 | ||
988 | rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); | 988 | rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); |
989 | if ((rt2x00_get_field32(reg, WLAN_EN) == 1)) | 989 | if (rt2x00_get_field32(reg, WLAN_EN)) |
990 | return 0; | 990 | return 0; |
991 | 991 | ||
992 | rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); | 992 | rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); |
@@ -1004,9 +1004,9 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) | |||
1004 | */ | 1004 | */ |
1005 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | 1005 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { |
1006 | rt2800_register_read(rt2x00dev, CMB_CTRL, ®); | 1006 | rt2800_register_read(rt2x00dev, CMB_CTRL, ®); |
1007 | if ((rt2x00_get_field32(reg, PLL_LD) == 1) && | 1007 | if (rt2x00_get_field32(reg, PLL_LD) && |
1008 | (rt2x00_get_field32(reg, XTAL_RDY) == 1)) | 1008 | rt2x00_get_field32(reg, XTAL_RDY)) |
1009 | break; | 1009 | break; |
1010 | udelay(REGISTER_BUSY_DELAY); | 1010 | udelay(REGISTER_BUSY_DELAY); |
1011 | } | 1011 | } |
1012 | 1012 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2fd830103415..f7e74a0a7759 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -774,9 +774,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, | |||
774 | bool rt2x00queue_for_each_entry(struct data_queue *queue, | 774 | bool rt2x00queue_for_each_entry(struct data_queue *queue, |
775 | enum queue_index start, | 775 | enum queue_index start, |
776 | enum queue_index end, | 776 | enum queue_index end, |
777 | void *data, | 777 | bool (*fn)(struct queue_entry *entry)) |
778 | bool (*fn)(struct queue_entry *entry, | ||
779 | void *data)) | ||
780 | { | 778 | { |
781 | unsigned long irqflags; | 779 | unsigned long irqflags; |
782 | unsigned int index_start; | 780 | unsigned int index_start; |
@@ -807,17 +805,17 @@ bool rt2x00queue_for_each_entry(struct data_queue *queue, | |||
807 | */ | 805 | */ |
808 | if (index_start < index_end) { | 806 | if (index_start < index_end) { |
809 | for (i = index_start; i < index_end; i++) { | 807 | for (i = index_start; i < index_end; i++) { |
810 | if (fn(&queue->entries[i], data)) | 808 | if (fn(&queue->entries[i])) |
811 | return true; | 809 | return true; |
812 | } | 810 | } |
813 | } else { | 811 | } else { |
814 | for (i = index_start; i < queue->limit; i++) { | 812 | for (i = index_start; i < queue->limit; i++) { |
815 | if (fn(&queue->entries[i], data)) | 813 | if (fn(&queue->entries[i])) |
816 | return true; | 814 | return true; |
817 | } | 815 | } |
818 | 816 | ||
819 | for (i = 0; i < index_end; i++) { | 817 | for (i = 0; i < index_end; i++) { |
820 | if (fn(&queue->entries[i], data)) | 818 | if (fn(&queue->entries[i])) |
821 | return true; | 819 | return true; |
822 | } | 820 | } |
823 | } | 821 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 5f1392c72673..9b8c10a86dee 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h | |||
@@ -584,7 +584,6 @@ struct data_queue_desc { | |||
584 | * @queue: Pointer to @data_queue | 584 | * @queue: Pointer to @data_queue |
585 | * @start: &enum queue_index Pointer to start index | 585 | * @start: &enum queue_index Pointer to start index |
586 | * @end: &enum queue_index Pointer to end index | 586 | * @end: &enum queue_index Pointer to end index |
587 | * @data: Data to pass to the callback function | ||
588 | * @fn: The function to call for each &struct queue_entry | 587 | * @fn: The function to call for each &struct queue_entry |
589 | * | 588 | * |
590 | * This will walk through all entries in the queue, in chronological | 589 | * This will walk through all entries in the queue, in chronological |
@@ -597,9 +596,7 @@ struct data_queue_desc { | |||
597 | bool rt2x00queue_for_each_entry(struct data_queue *queue, | 596 | bool rt2x00queue_for_each_entry(struct data_queue *queue, |
598 | enum queue_index start, | 597 | enum queue_index start, |
599 | enum queue_index end, | 598 | enum queue_index end, |
600 | void *data, | 599 | bool (*fn)(struct queue_entry *entry)); |
601 | bool (*fn)(struct queue_entry *entry, | ||
602 | void *data)); | ||
603 | 600 | ||
604 | /** | 601 | /** |
605 | * rt2x00queue_empty - Check if the queue is empty. | 602 | * rt2x00queue_empty - Check if the queue is empty. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 74ecc33fdd90..40ea80725a96 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c | |||
@@ -285,7 +285,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) | |||
285 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); | 285 | queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); |
286 | } | 286 | } |
287 | 287 | ||
288 | static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) | 288 | static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry) |
289 | { | 289 | { |
290 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 290 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
291 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | 291 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); |
@@ -390,7 +390,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) | |||
390 | queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); | 390 | queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); |
391 | } | 391 | } |
392 | 392 | ||
393 | static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) | 393 | static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry) |
394 | { | 394 | { |
395 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 395 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
396 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); | 396 | struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); |
@@ -427,18 +427,12 @@ void rt2x00usb_kick_queue(struct data_queue *queue) | |||
427 | case QID_AC_BE: | 427 | case QID_AC_BE: |
428 | case QID_AC_BK: | 428 | case QID_AC_BK: |
429 | if (!rt2x00queue_empty(queue)) | 429 | if (!rt2x00queue_empty(queue)) |
430 | rt2x00queue_for_each_entry(queue, | 430 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, |
431 | Q_INDEX_DONE, | ||
432 | Q_INDEX, | ||
433 | NULL, | ||
434 | rt2x00usb_kick_tx_entry); | 431 | rt2x00usb_kick_tx_entry); |
435 | break; | 432 | break; |
436 | case QID_RX: | 433 | case QID_RX: |
437 | if (!rt2x00queue_full(queue)) | 434 | if (!rt2x00queue_full(queue)) |
438 | rt2x00queue_for_each_entry(queue, | 435 | rt2x00queue_for_each_entry(queue, Q_INDEX, Q_INDEX_DONE, |
439 | Q_INDEX, | ||
440 | Q_INDEX_DONE, | ||
441 | NULL, | ||
442 | rt2x00usb_kick_rx_entry); | 436 | rt2x00usb_kick_rx_entry); |
443 | break; | 437 | break; |
444 | default: | 438 | default: |
@@ -447,7 +441,7 @@ void rt2x00usb_kick_queue(struct data_queue *queue) | |||
447 | } | 441 | } |
448 | EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); | 442 | EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); |
449 | 443 | ||
450 | static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) | 444 | static bool rt2x00usb_flush_entry(struct queue_entry *entry) |
451 | { | 445 | { |
452 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; | 446 | struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; |
453 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; | 447 | struct queue_entry_priv_usb *entry_priv = entry->priv_data; |
@@ -474,7 +468,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) | |||
474 | unsigned int i; | 468 | unsigned int i; |
475 | 469 | ||
476 | if (drop) | 470 | if (drop) |
477 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, | 471 | rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, |
478 | rt2x00usb_flush_entry); | 472 | rt2x00usb_flush_entry); |
479 | 473 | ||
480 | /* | 474 | /* |
@@ -565,7 +559,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) | |||
565 | entry->flags = 0; | 559 | entry->flags = 0; |
566 | 560 | ||
567 | if (entry->queue->qid == QID_RX) | 561 | if (entry->queue->qid == QID_RX) |
568 | rt2x00usb_kick_rx_entry(entry, NULL); | 562 | rt2x00usb_kick_rx_entry(entry); |
569 | } | 563 | } |
570 | EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); | 564 | EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); |
571 | 565 | ||
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 47ba2e0017f4..3d6c71b7a3c7 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c | |||
@@ -242,7 +242,7 @@ static struct wlcore_conf wl12xx_conf = { | |||
242 | .psm_entry_retries = 8, | 242 | .psm_entry_retries = 8, |
243 | .psm_exit_retries = 16, | 243 | .psm_exit_retries = 16, |
244 | .psm_entry_nullfunc_retries = 3, | 244 | .psm_entry_nullfunc_retries = 3, |
245 | .dynamic_ps_timeout = 200, | 245 | .dynamic_ps_timeout = 1500, |
246 | .forced_ps = false, | 246 | .forced_ps = false, |
247 | .keep_alive_interval = 55000, | 247 | .keep_alive_interval = 55000, |
248 | .max_listen_interval = 20, | 248 | .max_listen_interval = 20, |
@@ -590,13 +590,13 @@ static const int wl12xx_rtable[REG_TABLE_LEN] = { | |||
590 | }; | 590 | }; |
591 | 591 | ||
592 | /* TODO: maybe move to a new header file? */ | 592 | /* TODO: maybe move to a new header file? */ |
593 | #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" | 593 | #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-5-mr.bin" |
594 | #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" | 594 | #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-5-sr.bin" |
595 | #define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" | 595 | #define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-5-plt.bin" |
596 | 596 | ||
597 | #define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" | 597 | #define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-5-mr.bin" |
598 | #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" | 598 | #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-5-sr.bin" |
599 | #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" | 599 | #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-5-plt.bin" |
600 | 600 | ||
601 | static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) | 601 | static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) |
602 | { | 602 | { |
@@ -637,6 +637,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
637 | wl->chip.id); | 637 | wl->chip.id); |
638 | 638 | ||
639 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | | 639 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | |
640 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | ||
640 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 641 | WLCORE_QUIRK_TKIP_HEADER_SPACE; |
641 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | 642 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; |
642 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; | 643 | wl->mr_fw_name = WL127X_FW_NAME_MULTI; |
@@ -646,6 +647,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
646 | /* read data preparation is only needed by wl127x */ | 647 | /* read data preparation is only needed by wl127x */ |
647 | wl->ops->prepare_read = wl127x_prepare_read; | 648 | wl->ops->prepare_read = wl127x_prepare_read; |
648 | 649 | ||
650 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, | ||
651 | WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, | ||
652 | WL127X_MINOR_VER); | ||
649 | break; | 653 | break; |
650 | 654 | ||
651 | case CHIP_ID_1271_PG20: | 655 | case CHIP_ID_1271_PG20: |
@@ -653,6 +657,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
653 | wl->chip.id); | 657 | wl->chip.id); |
654 | 658 | ||
655 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | | 659 | wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | |
660 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | ||
656 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 661 | WLCORE_QUIRK_TKIP_HEADER_SPACE; |
657 | wl->plt_fw_name = WL127X_PLT_FW_NAME; | 662 | wl->plt_fw_name = WL127X_PLT_FW_NAME; |
658 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; | 663 | wl->sr_fw_name = WL127X_FW_NAME_SINGLE; |
@@ -663,6 +668,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
663 | /* read data preparation is only needed by wl127x */ | 668 | /* read data preparation is only needed by wl127x */ |
664 | wl->ops->prepare_read = wl127x_prepare_read; | 669 | wl->ops->prepare_read = wl127x_prepare_read; |
665 | 670 | ||
671 | wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, | ||
672 | WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, | ||
673 | WL127X_MINOR_VER); | ||
666 | break; | 674 | break; |
667 | 675 | ||
668 | case CHIP_ID_1283_PG20: | 676 | case CHIP_ID_1283_PG20: |
@@ -674,8 +682,12 @@ static int wl12xx_identify_chip(struct wl1271 *wl) | |||
674 | 682 | ||
675 | /* wl128x requires TX blocksize alignment */ | 683 | /* wl128x requires TX blocksize alignment */ |
676 | wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | | 684 | wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | |
685 | WLCORE_QUIRK_DUAL_PROBE_TMPL | | ||
677 | WLCORE_QUIRK_TKIP_HEADER_SPACE; | 686 | WLCORE_QUIRK_TKIP_HEADER_SPACE; |
678 | 687 | ||
688 | wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER, | ||
689 | WL128X_MAJOR_VER, WL128X_SUBTYPE_VER, | ||
690 | WL128X_MINOR_VER); | ||
679 | break; | 691 | break; |
680 | case CHIP_ID_1283_PG10: | 692 | case CHIP_ID_1283_PG10: |
681 | default: | 693 | default: |
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index de1132410876..26990fb4edea 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h | |||
@@ -24,6 +24,20 @@ | |||
24 | 24 | ||
25 | #include "conf.h" | 25 | #include "conf.h" |
26 | 26 | ||
27 | /* minimum FW required for driver for wl127x */ | ||
28 | #define WL127X_CHIP_VER 6 | ||
29 | #define WL127X_IFTYPE_VER 3 | ||
30 | #define WL127X_MAJOR_VER 10 | ||
31 | #define WL127X_SUBTYPE_VER 2 | ||
32 | #define WL127X_MINOR_VER 115 | ||
33 | |||
34 | /* minimum FW required for driver for wl128x */ | ||
35 | #define WL128X_CHIP_VER 7 | ||
36 | #define WL128X_IFTYPE_VER 3 | ||
37 | #define WL128X_MAJOR_VER 10 | ||
38 | #define WL128X_SUBTYPE_VER 2 | ||
39 | #define WL128X_MINOR_VER 115 | ||
40 | |||
27 | struct wl127x_rx_mem_pool_addr { | 41 | struct wl127x_rx_mem_pool_addr { |
28 | u32 addr; | 42 | u32 addr; |
29 | u32 addr_extra; | 43 | u32 addr_extra; |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 5e583be8f674..b378b34c4a6a 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -369,7 +369,7 @@ static struct wlcore_conf wl18xx_conf = { | |||
369 | .psm_entry_retries = 8, | 369 | .psm_entry_retries = 8, |
370 | .psm_exit_retries = 16, | 370 | .psm_exit_retries = 16, |
371 | .psm_entry_nullfunc_retries = 3, | 371 | .psm_entry_nullfunc_retries = 3, |
372 | .dynamic_ps_timeout = 200, | 372 | .dynamic_ps_timeout = 1500, |
373 | .forced_ps = false, | 373 | .forced_ps = false, |
374 | .keep_alive_interval = 55000, | 374 | .keep_alive_interval = 55000, |
375 | .max_listen_interval = 20, | 375 | .max_listen_interval = 20, |
@@ -609,7 +609,12 @@ static int wl18xx_identify_chip(struct wl1271 *wl) | |||
609 | wl->quirks |= WLCORE_QUIRK_NO_ELP | | 609 | wl->quirks |= WLCORE_QUIRK_NO_ELP | |
610 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | | 610 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | |
611 | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | | 611 | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | |
612 | WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN | | ||
612 | WLCORE_QUIRK_TX_PAD_LAST_FRAME; | 613 | WLCORE_QUIRK_TX_PAD_LAST_FRAME; |
614 | |||
615 | wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER, | ||
616 | WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER, | ||
617 | WL18XX_MINOR_VER); | ||
613 | break; | 618 | break; |
614 | case CHIP_ID_185x_PG10: | 619 | case CHIP_ID_185x_PG10: |
615 | wl1271_warning("chip id 0x%x (185x PG10) is deprecated", | 620 | wl1271_warning("chip id 0x%x (185x PG10) is deprecated", |
@@ -1020,14 +1025,24 @@ static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, | |||
1020 | static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, | 1025 | static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, |
1021 | struct wl12xx_vif *wlvif) | 1026 | struct wl12xx_vif *wlvif) |
1022 | { | 1027 | { |
1023 | if ((wlvif->channel_type == NL80211_CHAN_HT40MINUS || | 1028 | struct wl18xx_priv *priv = wl->priv; |
1024 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) && | 1029 | |
1025 | !strcmp(ht_mode_param, "wide")) { | 1030 | if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || |
1031 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) { | ||
1026 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); | 1032 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); |
1033 | |||
1034 | /* sanity check - we don't support this */ | ||
1035 | if (WARN_ON(wlvif->band != IEEE80211_BAND_5GHZ)) | ||
1036 | return 0; | ||
1037 | |||
1027 | return CONF_TX_RATE_USE_WIDE_CHAN; | 1038 | return CONF_TX_RATE_USE_WIDE_CHAN; |
1028 | } else if (!strcmp(ht_mode_param, "mimo")) { | 1039 | } else if (priv->conf.phy.number_of_assembled_ant2_4 >= 2 && |
1040 | wlvif->band == IEEE80211_BAND_2GHZ) { | ||
1029 | wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); | 1041 | wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); |
1030 | 1042 | /* | |
1043 | * we don't care about HT channel here - if a peer doesn't | ||
1044 | * support MIMO, we won't enable it in its rates | ||
1045 | */ | ||
1031 | return CONF_TX_MIMO_RATES; | 1046 | return CONF_TX_MIMO_RATES; |
1032 | } else { | 1047 | } else { |
1033 | return 0; | 1048 | return 0; |
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index bc67a4750615..6452396fa1d4 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h | |||
@@ -24,6 +24,13 @@ | |||
24 | 24 | ||
25 | #include "conf.h" | 25 | #include "conf.h" |
26 | 26 | ||
27 | /* minimum FW required for driver */ | ||
28 | #define WL18XX_CHIP_VER 8 | ||
29 | #define WL18XX_IFTYPE_VER 2 | ||
30 | #define WL18XX_MAJOR_VER 0 | ||
31 | #define WL18XX_SUBTYPE_VER 0 | ||
32 | #define WL18XX_MINOR_VER 100 | ||
33 | |||
27 | #define WL18XX_CMD_MAX_SIZE 740 | 34 | #define WL18XX_CMD_MAX_SIZE 740 |
28 | 35 | ||
29 | struct wl18xx_priv { | 36 | struct wl18xx_priv { |
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 8965960b841a..375ea574eafb 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c | |||
@@ -81,6 +81,53 @@ out: | |||
81 | return ret; | 81 | return ret; |
82 | } | 82 | } |
83 | 83 | ||
84 | static int wlcore_validate_fw_ver(struct wl1271 *wl) | ||
85 | { | ||
86 | unsigned int *fw_ver = wl->chip.fw_ver; | ||
87 | unsigned int *min_ver = wl->min_fw_ver; | ||
88 | |||
89 | /* the chip must be exactly equal */ | ||
90 | if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]) | ||
91 | goto fail; | ||
92 | |||
93 | /* always check the next digit if all previous ones are equal */ | ||
94 | |||
95 | if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE]) | ||
96 | goto out; | ||
97 | else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE]) | ||
98 | goto fail; | ||
99 | |||
100 | if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR]) | ||
101 | goto out; | ||
102 | else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]) | ||
103 | goto fail; | ||
104 | |||
105 | if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE]) | ||
106 | goto out; | ||
107 | else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE]) | ||
108 | goto fail; | ||
109 | |||
110 | if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR]) | ||
111 | goto out; | ||
112 | else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]) | ||
113 | goto fail; | ||
114 | |||
115 | out: | ||
116 | return 0; | ||
117 | |||
118 | fail: | ||
119 | wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n" | ||
120 | "Please use at least FW %u.%u.%u.%u.%u.\n" | ||
121 | "You can get more information at:\n" | ||
122 | "http://wireless.kernel.org/en/users/Drivers/wl12xx", | ||
123 | fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], | ||
124 | fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], | ||
125 | fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP], | ||
126 | min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR], | ||
127 | min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | |||
84 | static int wlcore_boot_static_data(struct wl1271 *wl) | 131 | static int wlcore_boot_static_data(struct wl1271 *wl) |
85 | { | 132 | { |
86 | struct wl1271_static_data *static_data; | 133 | struct wl1271_static_data *static_data; |
@@ -101,6 +148,10 @@ static int wlcore_boot_static_data(struct wl1271 *wl) | |||
101 | if (ret < 0) | 148 | if (ret < 0) |
102 | goto out_free; | 149 | goto out_free; |
103 | 150 | ||
151 | ret = wlcore_validate_fw_ver(wl); | ||
152 | if (ret < 0) | ||
153 | goto out_free; | ||
154 | |||
104 | ret = wlcore_handle_static_data(wl, static_data); | 155 | ret = wlcore_handle_static_data(wl, static_data); |
105 | if (ret < 0) | 156 | if (ret < 0) |
106 | goto out_free; | 157 | goto out_free; |
@@ -141,7 +192,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, | |||
141 | partition.mem.start = dest; | 192 | partition.mem.start = dest; |
142 | ret = wlcore_set_partition(wl, &partition); | 193 | ret = wlcore_set_partition(wl, &partition); |
143 | if (ret < 0) | 194 | if (ret < 0) |
144 | return ret; | 195 | goto out; |
145 | 196 | ||
146 | /* 10.1 set partition limit and chunk num */ | 197 | /* 10.1 set partition limit and chunk num */ |
147 | chunk_num = 0; | 198 | chunk_num = 0; |
@@ -157,7 +208,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, | |||
157 | partition.mem.start = addr; | 208 | partition.mem.start = addr; |
158 | ret = wlcore_set_partition(wl, &partition); | 209 | ret = wlcore_set_partition(wl, &partition); |
159 | if (ret < 0) | 210 | if (ret < 0) |
160 | return ret; | 211 | goto out; |
161 | } | 212 | } |
162 | 213 | ||
163 | /* 10.3 upload the chunk */ | 214 | /* 10.3 upload the chunk */ |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 56c7a2342fdf..a23949cdaebc 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "hw_ops.h" | 39 | #include "hw_ops.h" |
40 | 40 | ||
41 | #define WL1271_CMD_FAST_POLL_COUNT 50 | 41 | #define WL1271_CMD_FAST_POLL_COUNT 50 |
42 | #define WL1271_WAIT_EVENT_FAST_POLL_COUNT 20 | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * send command to firmware | 45 | * send command to firmware |
@@ -138,6 +139,7 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, | |||
138 | u32 *events_vector; | 139 | u32 *events_vector; |
139 | u32 event; | 140 | u32 event; |
140 | unsigned long timeout_time; | 141 | unsigned long timeout_time; |
142 | u16 poll_count = 0; | ||
141 | int ret = 0; | 143 | int ret = 0; |
142 | 144 | ||
143 | *timeout = false; | 145 | *timeout = false; |
@@ -156,7 +158,11 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, | |||
156 | goto out; | 158 | goto out; |
157 | } | 159 | } |
158 | 160 | ||
159 | msleep(1); | 161 | poll_count++; |
162 | if (poll_count < WL1271_WAIT_EVENT_FAST_POLL_COUNT) | ||
163 | usleep_range(50, 51); | ||
164 | else | ||
165 | usleep_range(1000, 5000); | ||
160 | 166 | ||
161 | /* read from both event fields */ | 167 | /* read from both event fields */ |
162 | ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector, | 168 | ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector, |
@@ -1007,12 +1013,14 @@ out: | |||
1007 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 1013 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
1008 | u8 role_id, u8 band, | 1014 | u8 role_id, u8 band, |
1009 | const u8 *ssid, size_t ssid_len, | 1015 | const u8 *ssid, size_t ssid_len, |
1010 | const u8 *ie, size_t ie_len) | 1016 | const u8 *ie, size_t ie_len, bool sched_scan) |
1011 | { | 1017 | { |
1012 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); | 1018 | struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); |
1013 | struct sk_buff *skb; | 1019 | struct sk_buff *skb; |
1014 | int ret; | 1020 | int ret; |
1015 | u32 rate; | 1021 | u32 rate; |
1022 | u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; | ||
1023 | u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; | ||
1016 | 1024 | ||
1017 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, | 1025 | skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, |
1018 | ie, ie_len); | 1026 | ie, ie_len); |
@@ -1023,14 +1031,20 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
1023 | 1031 | ||
1024 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); | 1032 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); |
1025 | 1033 | ||
1034 | if (!sched_scan && | ||
1035 | (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { | ||
1036 | template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4; | ||
1037 | template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5; | ||
1038 | } | ||
1039 | |||
1026 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); | 1040 | rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); |
1027 | if (band == IEEE80211_BAND_2GHZ) | 1041 | if (band == IEEE80211_BAND_2GHZ) |
1028 | ret = wl1271_cmd_template_set(wl, role_id, | 1042 | ret = wl1271_cmd_template_set(wl, role_id, |
1029 | CMD_TEMPL_CFG_PROBE_REQ_2_4, | 1043 | template_id_2_4, |
1030 | skb->data, skb->len, 0, rate); | 1044 | skb->data, skb->len, 0, rate); |
1031 | else | 1045 | else |
1032 | ret = wl1271_cmd_template_set(wl, role_id, | 1046 | ret = wl1271_cmd_template_set(wl, role_id, |
1033 | CMD_TEMPL_CFG_PROBE_REQ_5, | 1047 | template_id_5, |
1034 | skb->data, skb->len, 0, rate); | 1048 | skb->data, skb->len, 0, rate); |
1035 | 1049 | ||
1036 | out: | 1050 | out: |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index c8a6510c72cb..d7d9f801e506 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h | |||
@@ -58,7 +58,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
58 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, | 58 | int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
59 | u8 role_id, u8 band, | 59 | u8 role_id, u8 band, |
60 | const u8 *ssid, size_t ssid_len, | 60 | const u8 *ssid, size_t ssid_len, |
61 | const u8 *ie, size_t ie_len); | 61 | const u8 *ie, size_t ie_len, bool sched_scan); |
62 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | 62 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, |
63 | struct wl12xx_vif *wlvif, | 63 | struct wl12xx_vif *wlvif, |
64 | struct sk_buff *skb); | 64 | struct sk_buff *skb); |
@@ -172,8 +172,8 @@ enum cmd_templ { | |||
172 | CMD_TEMPL_PS_POLL, | 172 | CMD_TEMPL_PS_POLL, |
173 | CMD_TEMPL_KLV, | 173 | CMD_TEMPL_KLV, |
174 | CMD_TEMPL_DISCONNECT, | 174 | CMD_TEMPL_DISCONNECT, |
175 | CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ | 175 | CMD_TEMPL_APP_PROBE_REQ_2_4, |
176 | CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ | 176 | CMD_TEMPL_APP_PROBE_REQ_5, |
177 | CMD_TEMPL_BAR, /* for firmware internal use only */ | 177 | CMD_TEMPL_BAR, /* for firmware internal use only */ |
178 | CMD_TEMPL_CTS, /* | 178 | CMD_TEMPL_CTS, /* |
179 | * For CTS-to-self (FastCTS) mechanism | 179 | * For CTS-to-self (FastCTS) mechanism |
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 8a8a8971befa..a3c867786df8 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c | |||
@@ -54,6 +54,22 @@ int wl1271_init_templates_config(struct wl1271 *wl) | |||
54 | if (ret < 0) | 54 | if (ret < 0) |
55 | return ret; | 55 | return ret; |
56 | 56 | ||
57 | if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) { | ||
58 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
59 | CMD_TEMPL_APP_PROBE_REQ_2_4, NULL, | ||
60 | WL1271_CMD_TEMPL_MAX_SIZE, | ||
61 | 0, WL1271_RATE_AUTOMATIC); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | |||
65 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | ||
66 | CMD_TEMPL_APP_PROBE_REQ_5, NULL, | ||
67 | WL1271_CMD_TEMPL_MAX_SIZE, | ||
68 | 0, WL1271_RATE_AUTOMATIC); | ||
69 | if (ret < 0) | ||
70 | return ret; | ||
71 | } | ||
72 | |||
57 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, | 73 | ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, |
58 | CMD_TEMPL_NULL_DATA, NULL, | 74 | CMD_TEMPL_NULL_DATA, NULL, |
59 | sizeof(struct wl12xx_null_data_template), | 75 | sizeof(struct wl12xx_null_data_template), |
diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c index 9976219c4e49..68e74eefd296 100644 --- a/drivers/net/wireless/ti/wlcore/io.c +++ b/drivers/net/wireless/ti/wlcore/io.c | |||
@@ -60,6 +60,12 @@ void wlcore_enable_interrupts(struct wl1271 *wl) | |||
60 | } | 60 | } |
61 | EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); | 61 | EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); |
62 | 62 | ||
63 | void wlcore_synchronize_interrupts(struct wl1271 *wl) | ||
64 | { | ||
65 | synchronize_irq(wl->irq); | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts); | ||
68 | |||
63 | int wlcore_translate_addr(struct wl1271 *wl, int addr) | 69 | int wlcore_translate_addr(struct wl1271 *wl, int addr) |
64 | { | 70 | { |
65 | struct wlcore_partition_set *part = &wl->curr_part; | 71 | struct wlcore_partition_set *part = &wl->curr_part; |
diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index fef80adc8bf5..259149f36fae 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h | |||
@@ -47,6 +47,7 @@ struct wl1271; | |||
47 | void wlcore_disable_interrupts(struct wl1271 *wl); | 47 | void wlcore_disable_interrupts(struct wl1271 *wl); |
48 | void wlcore_disable_interrupts_nosync(struct wl1271 *wl); | 48 | void wlcore_disable_interrupts_nosync(struct wl1271 *wl); |
49 | void wlcore_enable_interrupts(struct wl1271 *wl); | 49 | void wlcore_enable_interrupts(struct wl1271 *wl); |
50 | void wlcore_synchronize_interrupts(struct wl1271 *wl); | ||
50 | 51 | ||
51 | void wl1271_io_reset(struct wl1271 *wl); | 52 | void wl1271_io_reset(struct wl1271 *wl); |
52 | void wl1271_io_init(struct wl1271 *wl); | 53 | void wl1271_io_init(struct wl1271 *wl); |
@@ -59,12 +60,12 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr, | |||
59 | { | 60 | { |
60 | int ret; | 61 | int ret; |
61 | 62 | ||
62 | if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags)) | 63 | if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) |
63 | return -EIO; | 64 | return -EIO; |
64 | 65 | ||
65 | ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); | 66 | ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); |
66 | if (ret) | 67 | if (ret && wl->state != WL1271_STATE_OFF) |
67 | set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags); | 68 | set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); |
68 | 69 | ||
69 | return ret; | 70 | return ret; |
70 | } | 71 | } |
@@ -75,12 +76,12 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr, | |||
75 | { | 76 | { |
76 | int ret; | 77 | int ret; |
77 | 78 | ||
78 | if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags)) | 79 | if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) |
79 | return -EIO; | 80 | return -EIO; |
80 | 81 | ||
81 | ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); | 82 | ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); |
82 | if (ret) | 83 | if (ret && wl->state != WL1271_STATE_OFF) |
83 | set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags); | 84 | set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); |
84 | 85 | ||
85 | return ret; | 86 | return ret; |
86 | } | 87 | } |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2240cca597ac..9f04b64dfa33 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -62,7 +62,7 @@ static bool no_recovery; | |||
62 | static void __wl1271_op_remove_interface(struct wl1271 *wl, | 62 | static void __wl1271_op_remove_interface(struct wl1271 *wl, |
63 | struct ieee80211_vif *vif, | 63 | struct ieee80211_vif *vif, |
64 | bool reset_tx_queues); | 64 | bool reset_tx_queues); |
65 | static void wl1271_op_stop(struct ieee80211_hw *hw); | 65 | static void wlcore_op_stop_locked(struct wl1271 *wl); |
66 | static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); | 66 | static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); |
67 | 67 | ||
68 | static int wl12xx_set_authorized(struct wl1271 *wl, | 68 | static int wl12xx_set_authorized(struct wl1271 *wl, |
@@ -916,16 +916,16 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
916 | if (wl->state != WL1271_STATE_ON || wl->plt) | 916 | if (wl->state != WL1271_STATE_ON || wl->plt) |
917 | goto out_unlock; | 917 | goto out_unlock; |
918 | 918 | ||
919 | wl12xx_read_fwlog_panic(wl); | 919 | if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { |
920 | 920 | wl12xx_read_fwlog_panic(wl); | |
921 | wlcore_print_recovery(wl); | 921 | wlcore_print_recovery(wl); |
922 | } | ||
922 | 923 | ||
923 | BUG_ON(bug_on_recovery && | 924 | BUG_ON(bug_on_recovery && |
924 | !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); | 925 | !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); |
925 | 926 | ||
926 | if (no_recovery) { | 927 | if (no_recovery) { |
927 | wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); | 928 | wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); |
928 | clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); | ||
929 | goto out_unlock; | 929 | goto out_unlock; |
930 | } | 930 | } |
931 | 931 | ||
@@ -956,9 +956,8 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
956 | vif = wl12xx_wlvif_to_vif(wlvif); | 956 | vif = wl12xx_wlvif_to_vif(wlvif); |
957 | __wl1271_op_remove_interface(wl, vif, false); | 957 | __wl1271_op_remove_interface(wl, vif, false); |
958 | } | 958 | } |
959 | wl->watchdog_recovery = false; | 959 | |
960 | mutex_unlock(&wl->mutex); | 960 | wlcore_op_stop_locked(wl); |
961 | wl1271_op_stop(wl->hw); | ||
962 | 961 | ||
963 | ieee80211_restart_hw(wl->hw); | 962 | ieee80211_restart_hw(wl->hw); |
964 | 963 | ||
@@ -967,9 +966,10 @@ static void wl1271_recovery_work(struct work_struct *work) | |||
967 | * to restart the HW. | 966 | * to restart the HW. |
968 | */ | 967 | */ |
969 | wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); | 968 | wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); |
970 | return; | 969 | |
971 | out_unlock: | 970 | out_unlock: |
972 | wl->watchdog_recovery = false; | 971 | wl->watchdog_recovery = false; |
972 | clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); | ||
973 | mutex_unlock(&wl->mutex); | 973 | mutex_unlock(&wl->mutex); |
974 | } | 974 | } |
975 | 975 | ||
@@ -1211,7 +1211,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1211 | * The workqueue is slow to process the tx_queue and we need stop | 1211 | * The workqueue is slow to process the tx_queue and we need stop |
1212 | * the queue here, otherwise the queue will get too long. | 1212 | * the queue here, otherwise the queue will get too long. |
1213 | */ | 1213 | */ |
1214 | if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { | 1214 | if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && |
1215 | !wlcore_is_queue_stopped_by_reason(wl, q, | ||
1216 | WLCORE_QUEUE_STOP_REASON_WATERMARK)) { | ||
1215 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); | 1217 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); |
1216 | wlcore_stop_queue_locked(wl, q, | 1218 | wlcore_stop_queue_locked(wl, q, |
1217 | WLCORE_QUEUE_STOP_REASON_WATERMARK); | 1219 | WLCORE_QUEUE_STOP_REASON_WATERMARK); |
@@ -1797,33 +1799,15 @@ static int wl1271_op_start(struct ieee80211_hw *hw) | |||
1797 | return 0; | 1799 | return 0; |
1798 | } | 1800 | } |
1799 | 1801 | ||
1800 | static void wl1271_op_stop(struct ieee80211_hw *hw) | 1802 | static void wlcore_op_stop_locked(struct wl1271 *wl) |
1801 | { | 1803 | { |
1802 | struct wl1271 *wl = hw->priv; | ||
1803 | int i; | 1804 | int i; |
1804 | 1805 | ||
1805 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
1806 | |||
1807 | /* | ||
1808 | * Interrupts must be disabled before setting the state to OFF. | ||
1809 | * Otherwise, the interrupt handler might be called and exit without | ||
1810 | * reading the interrupt status. | ||
1811 | */ | ||
1812 | wlcore_disable_interrupts(wl); | ||
1813 | mutex_lock(&wl->mutex); | ||
1814 | if (wl->state == WL1271_STATE_OFF) { | 1806 | if (wl->state == WL1271_STATE_OFF) { |
1815 | if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, | 1807 | if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, |
1816 | &wl->flags)) | 1808 | &wl->flags)) |
1817 | wlcore_enable_interrupts(wl); | 1809 | wlcore_enable_interrupts(wl); |
1818 | 1810 | ||
1819 | mutex_unlock(&wl->mutex); | ||
1820 | |||
1821 | /* | ||
1822 | * This will not necessarily enable interrupts as interrupts | ||
1823 | * may have been disabled when op_stop was called. It will, | ||
1824 | * however, balance the above call to disable_interrupts(). | ||
1825 | */ | ||
1826 | wlcore_enable_interrupts(wl); | ||
1827 | return; | 1811 | return; |
1828 | } | 1812 | } |
1829 | 1813 | ||
@@ -1832,8 +1816,16 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1832 | * functions don't perform further work. | 1816 | * functions don't perform further work. |
1833 | */ | 1817 | */ |
1834 | wl->state = WL1271_STATE_OFF; | 1818 | wl->state = WL1271_STATE_OFF; |
1819 | |||
1820 | /* | ||
1821 | * Use the nosync variant to disable interrupts, so the mutex could be | ||
1822 | * held while doing so without deadlocking. | ||
1823 | */ | ||
1824 | wlcore_disable_interrupts_nosync(wl); | ||
1825 | |||
1835 | mutex_unlock(&wl->mutex); | 1826 | mutex_unlock(&wl->mutex); |
1836 | 1827 | ||
1828 | wlcore_synchronize_interrupts(wl); | ||
1837 | wl1271_flush_deferred_work(wl); | 1829 | wl1271_flush_deferred_work(wl); |
1838 | cancel_delayed_work_sync(&wl->scan_complete_work); | 1830 | cancel_delayed_work_sync(&wl->scan_complete_work); |
1839 | cancel_work_sync(&wl->netstack_work); | 1831 | cancel_work_sync(&wl->netstack_work); |
@@ -1900,6 +1892,17 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1900 | wl->tx_res_if = NULL; | 1892 | wl->tx_res_if = NULL; |
1901 | kfree(wl->target_mem_map); | 1893 | kfree(wl->target_mem_map); |
1902 | wl->target_mem_map = NULL; | 1894 | wl->target_mem_map = NULL; |
1895 | } | ||
1896 | |||
1897 | static void wlcore_op_stop(struct ieee80211_hw *hw) | ||
1898 | { | ||
1899 | struct wl1271 *wl = hw->priv; | ||
1900 | |||
1901 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
1902 | |||
1903 | mutex_lock(&wl->mutex); | ||
1904 | |||
1905 | wlcore_op_stop_locked(wl); | ||
1903 | 1906 | ||
1904 | mutex_unlock(&wl->mutex); | 1907 | mutex_unlock(&wl->mutex); |
1905 | } | 1908 | } |
@@ -4566,7 +4569,7 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, | |||
4566 | 4569 | ||
4567 | mutex_lock(&wl->mutex); | 4570 | mutex_lock(&wl->mutex); |
4568 | 4571 | ||
4569 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | 4572 | for (i = 0; i < WLCORE_NUM_BANDS; i++) |
4570 | wlvif->bitrate_masks[i] = | 4573 | wlvif->bitrate_masks[i] = |
4571 | wl1271_tx_enabled_rates_get(wl, | 4574 | wl1271_tx_enabled_rates_get(wl, |
4572 | mask->control[i].legacy, | 4575 | mask->control[i].legacy, |
@@ -4634,6 +4637,13 @@ out: | |||
4634 | mutex_unlock(&wl->mutex); | 4637 | mutex_unlock(&wl->mutex); |
4635 | } | 4638 | } |
4636 | 4639 | ||
4640 | static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) | ||
4641 | { | ||
4642 | struct wl1271 *wl = hw->priv; | ||
4643 | |||
4644 | wl1271_tx_flush(wl); | ||
4645 | } | ||
4646 | |||
4637 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) | 4647 | static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) |
4638 | { | 4648 | { |
4639 | struct wl1271 *wl = hw->priv; | 4649 | struct wl1271 *wl = hw->priv; |
@@ -4796,7 +4806,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { | |||
4796 | 4806 | ||
4797 | static const struct ieee80211_ops wl1271_ops = { | 4807 | static const struct ieee80211_ops wl1271_ops = { |
4798 | .start = wl1271_op_start, | 4808 | .start = wl1271_op_start, |
4799 | .stop = wl1271_op_stop, | 4809 | .stop = wlcore_op_stop, |
4800 | .add_interface = wl1271_op_add_interface, | 4810 | .add_interface = wl1271_op_add_interface, |
4801 | .remove_interface = wl1271_op_remove_interface, | 4811 | .remove_interface = wl1271_op_remove_interface, |
4802 | .change_interface = wl12xx_op_change_interface, | 4812 | .change_interface = wl12xx_op_change_interface, |
@@ -4824,6 +4834,7 @@ static const struct ieee80211_ops wl1271_ops = { | |||
4824 | .tx_frames_pending = wl1271_tx_frames_pending, | 4834 | .tx_frames_pending = wl1271_tx_frames_pending, |
4825 | .set_bitrate_mask = wl12xx_set_bitrate_mask, | 4835 | .set_bitrate_mask = wl12xx_set_bitrate_mask, |
4826 | .channel_switch = wl12xx_op_channel_switch, | 4836 | .channel_switch = wl12xx_op_channel_switch, |
4837 | .flush = wlcore_op_flush, | ||
4827 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 4838 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
4828 | }; | 4839 | }; |
4829 | 4840 | ||
@@ -5504,6 +5515,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) | |||
5504 | goto out_free_hw; | 5515 | goto out_free_hw; |
5505 | } | 5516 | } |
5506 | 5517 | ||
5518 | #ifdef CONFIG_PM | ||
5507 | ret = enable_irq_wake(wl->irq); | 5519 | ret = enable_irq_wake(wl->irq); |
5508 | if (!ret) { | 5520 | if (!ret) { |
5509 | wl->irq_wake_enabled = true; | 5521 | wl->irq_wake_enabled = true; |
@@ -5517,6 +5529,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) | |||
5517 | WL1271_RX_FILTER_MAX_PATTERN_SIZE; | 5529 | WL1271_RX_FILTER_MAX_PATTERN_SIZE; |
5518 | } | 5530 | } |
5519 | } | 5531 | } |
5532 | #endif | ||
5520 | disable_irq(wl->irq); | 5533 | disable_irq(wl->irq); |
5521 | 5534 | ||
5522 | ret = wl12xx_get_hw_info(wl); | 5535 | ret = wl12xx_get_hw_info(wl); |
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index d9daed53ceb7..dbeca1bfbb2c 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c | |||
@@ -226,7 +226,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, | |||
226 | cmd->params.role_id, band, | 226 | cmd->params.role_id, band, |
227 | wl->scan.ssid, wl->scan.ssid_len, | 227 | wl->scan.ssid, wl->scan.ssid_len, |
228 | wl->scan.req->ie, | 228 | wl->scan.req->ie, |
229 | wl->scan.req->ie_len); | 229 | wl->scan.req->ie_len, false); |
230 | if (ret < 0) { | 230 | if (ret < 0) { |
231 | wl1271_error("PROBE request template failed"); | 231 | wl1271_error("PROBE request template failed"); |
232 | goto out; | 232 | goto out; |
@@ -633,7 +633,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, | |||
633 | 633 | ||
634 | for (j = 0; j < cmd->n_ssids; j++) | 634 | for (j = 0; j < cmd->n_ssids; j++) |
635 | if ((req->ssids[i].ssid_len == | 635 | if ((req->ssids[i].ssid_len == |
636 | req->ssids[j].ssid_len) && | 636 | cmd->ssids[j].len) && |
637 | !memcmp(req->ssids[i].ssid, | 637 | !memcmp(req->ssids[i].ssid, |
638 | cmd->ssids[j].ssid, | 638 | cmd->ssids[j].ssid, |
639 | req->ssids[i].ssid_len)) { | 639 | req->ssids[i].ssid_len)) { |
@@ -722,7 +722,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, | |||
722 | req->ssids[0].ssid, | 722 | req->ssids[0].ssid, |
723 | req->ssids[0].ssid_len, | 723 | req->ssids[0].ssid_len, |
724 | ies->ie[band], | 724 | ies->ie[band], |
725 | ies->len[band]); | 725 | ies->len[band], true); |
726 | if (ret < 0) { | 726 | if (ret < 0) { |
727 | wl1271_error("2.4GHz PROBE request template failed"); | 727 | wl1271_error("2.4GHz PROBE request template failed"); |
728 | goto out; | 728 | goto out; |
@@ -736,7 +736,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, | |||
736 | req->ssids[0].ssid, | 736 | req->ssids[0].ssid, |
737 | req->ssids[0].ssid_len, | 737 | req->ssids[0].ssid_len, |
738 | ies->ie[band], | 738 | ies->ie[band], |
739 | ies->len[band]); | 739 | ies->len[band], true); |
740 | if (ret < 0) { | 740 | if (ret < 0) { |
741 | wl1271_error("5GHz PROBE request template failed"); | 741 | wl1271_error("5GHz PROBE request template failed"); |
742 | goto out; | 742 | goto out; |
@@ -766,7 +766,8 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) | |||
766 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) | 766 | if (wlvif->bss_type != BSS_TYPE_STA_BSS) |
767 | return -EOPNOTSUPP; | 767 | return -EOPNOTSUPP; |
768 | 768 | ||
769 | if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | 769 | if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && |
770 | test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) | ||
770 | return -EBUSY; | 771 | return -EBUSY; |
771 | 772 | ||
772 | start = kzalloc(sizeof(*start), GFP_KERNEL); | 773 | start = kzalloc(sizeof(*start), GFP_KERNEL); |
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 204e69fa9327..73ace4b2604e 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c | |||
@@ -411,9 +411,3 @@ MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); | |||
411 | MODULE_LICENSE("GPL"); | 411 | MODULE_LICENSE("GPL"); |
412 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | 412 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); |
413 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 413 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
414 | MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); | ||
415 | MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); | ||
416 | MODULE_FIRMWARE(WL127X_PLT_FW_NAME); | ||
417 | MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); | ||
418 | MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); | ||
419 | MODULE_FIRMWARE(WL128X_PLT_FW_NAME); | ||
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 6420abae40ee..8da4ed243ebc 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c | |||
@@ -435,10 +435,4 @@ module_exit(wl1271_exit); | |||
435 | MODULE_LICENSE("GPL"); | 435 | MODULE_LICENSE("GPL"); |
436 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | 436 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); |
437 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 437 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
438 | MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); | ||
439 | MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); | ||
440 | MODULE_FIRMWARE(WL127X_PLT_FW_NAME); | ||
441 | MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); | ||
442 | MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); | ||
443 | MODULE_FIRMWARE(WL128X_PLT_FW_NAME); | ||
444 | MODULE_ALIAS("spi:wl1271"); | 438 | MODULE_ALIAS("spi:wl1271"); |
diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index eeb339d61d1e..d6f57e2c03cf 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c | |||
@@ -40,7 +40,7 @@ enum wl1271_tm_commands { | |||
40 | WL1271_TM_CMD_CONFIGURE, | 40 | WL1271_TM_CMD_CONFIGURE, |
41 | WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ | 41 | WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ |
42 | WL1271_TM_CMD_SET_PLT_MODE, | 42 | WL1271_TM_CMD_SET_PLT_MODE, |
43 | WL1271_TM_CMD_RECOVER, | 43 | WL1271_TM_CMD_RECOVER, /* Not in use. Keep to not break ABI */ |
44 | WL1271_TM_CMD_GET_MAC, | 44 | WL1271_TM_CMD_GET_MAC, |
45 | 45 | ||
46 | __WL1271_TM_CMD_AFTER_LAST | 46 | __WL1271_TM_CMD_AFTER_LAST |
@@ -272,15 +272,6 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) | |||
272 | return ret; | 272 | return ret; |
273 | } | 273 | } |
274 | 274 | ||
275 | static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) | ||
276 | { | ||
277 | wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); | ||
278 | |||
279 | wl12xx_queue_recovery_work(wl); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) | 275 | static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) |
285 | { | 276 | { |
286 | struct sk_buff *skb; | 277 | struct sk_buff *skb; |
@@ -350,8 +341,6 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) | |||
350 | return wl1271_tm_cmd_configure(wl, tb); | 341 | return wl1271_tm_cmd_configure(wl, tb); |
351 | case WL1271_TM_CMD_SET_PLT_MODE: | 342 | case WL1271_TM_CMD_SET_PLT_MODE: |
352 | return wl1271_tm_cmd_set_plt_mode(wl, tb); | 343 | return wl1271_tm_cmd_set_plt_mode(wl, tb); |
353 | case WL1271_TM_CMD_RECOVER: | ||
354 | return wl1271_tm_cmd_recover(wl, tb); | ||
355 | case WL1271_TM_CMD_GET_MAC: | 344 | case WL1271_TM_CMD_GET_MAC: |
356 | return wl12xx_tm_cmd_get_mac(wl, tb); | 345 | return wl12xx_tm_cmd_get_mac(wl, tb); |
357 | default: | 346 | default: |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index e796974df59b..27ccc275a1c1 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h | |||
@@ -304,7 +304,7 @@ struct wl1271 { | |||
304 | s8 noise; | 304 | s8 noise; |
305 | 305 | ||
306 | /* bands supported by this instance of wl12xx */ | 306 | /* bands supported by this instance of wl12xx */ |
307 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; | 307 | struct ieee80211_supported_band bands[WLCORE_NUM_BANDS]; |
308 | 308 | ||
309 | /* | 309 | /* |
310 | * wowlan trigger was configured during suspend. | 310 | * wowlan trigger was configured during suspend. |
@@ -371,7 +371,7 @@ struct wl1271 { | |||
371 | u8 hw_min_ht_rate; | 371 | u8 hw_min_ht_rate; |
372 | 372 | ||
373 | /* HW HT (11n) capabilities */ | 373 | /* HW HT (11n) capabilities */ |
374 | struct ieee80211_sta_ht_cap ht_cap[IEEE80211_NUM_BANDS]; | 374 | struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS]; |
375 | 375 | ||
376 | /* size of the private FW status data */ | 376 | /* size of the private FW status data */ |
377 | size_t fw_status_priv_len; | 377 | size_t fw_status_priv_len; |
@@ -390,6 +390,9 @@ struct wl1271 { | |||
390 | 390 | ||
391 | /* sleep auth value currently configured to FW */ | 391 | /* sleep auth value currently configured to FW */ |
392 | int sleep_auth; | 392 | int sleep_auth; |
393 | |||
394 | /* the minimum FW version required for the driver to work */ | ||
395 | unsigned int min_fw_ver[NUM_FW_VER]; | ||
393 | }; | 396 | }; |
394 | 397 | ||
395 | int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); | 398 | int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); |
@@ -408,6 +411,18 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, | |||
408 | memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); | 411 | memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); |
409 | } | 412 | } |
410 | 413 | ||
414 | static inline void | ||
415 | wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, | ||
416 | unsigned int iftype, unsigned int major, | ||
417 | unsigned int subtype, unsigned int minor) | ||
418 | { | ||
419 | wl->min_fw_ver[FW_VER_CHIP] = chip; | ||
420 | wl->min_fw_ver[FW_VER_IF_TYPE] = iftype; | ||
421 | wl->min_fw_ver[FW_VER_MAJOR] = major; | ||
422 | wl->min_fw_ver[FW_VER_SUBTYPE] = subtype; | ||
423 | wl->min_fw_ver[FW_VER_MINOR] = minor; | ||
424 | } | ||
425 | |||
411 | /* Firmware image load chunk size */ | 426 | /* Firmware image load chunk size */ |
412 | #define CHUNK_SIZE 16384 | 427 | #define CHUNK_SIZE 16384 |
413 | 428 | ||
@@ -437,6 +452,12 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, | |||
437 | /* extra header space is required for TKIP */ | 452 | /* extra header space is required for TKIP */ |
438 | #define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8) | 453 | #define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8) |
439 | 454 | ||
455 | /* Some firmwares not support sched scans while connected */ | ||
456 | #define WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN BIT(9) | ||
457 | |||
458 | /* separate probe response templates for one-shot and sched scans */ | ||
459 | #define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10) | ||
460 | |||
440 | /* TODO: move to the lower drivers when all usages are abstracted */ | 461 | /* TODO: move to the lower drivers when all usages are abstracted */ |
441 | #define CHIP_ID_1271_PG10 (0x4030101) | 462 | #define CHIP_ID_1271_PG10 (0x4030101) |
442 | #define CHIP_ID_1271_PG20 (0x4030111) | 463 | #define CHIP_ID_1271_PG20 (0x4030111) |
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 4273a21cdde1..0187eef4fb07 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h | |||
@@ -35,15 +35,6 @@ | |||
35 | #include "conf.h" | 35 | #include "conf.h" |
36 | #include "ini.h" | 36 | #include "ini.h" |
37 | 37 | ||
38 | #define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" | ||
39 | #define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" | ||
40 | |||
41 | #define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" | ||
42 | #define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" | ||
43 | |||
44 | #define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" | ||
45 | #define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" | ||
46 | |||
47 | /* | 38 | /* |
48 | * wl127x and wl128x are using the same NVS file name. However, the | 39 | * wl127x and wl128x are using the same NVS file name. However, the |
49 | * ini parameters between them are different. The driver validates | 40 | * ini parameters between them are different. The driver validates |
@@ -71,6 +62,9 @@ | |||
71 | #define WL12XX_INVALID_ROLE_ID 0xff | 62 | #define WL12XX_INVALID_ROLE_ID 0xff |
72 | #define WL12XX_INVALID_LINK_ID 0xff | 63 | #define WL12XX_INVALID_LINK_ID 0xff |
73 | 64 | ||
65 | /* the driver supports the 2.4Ghz and 5Ghz bands */ | ||
66 | #define WLCORE_NUM_BANDS 2 | ||
67 | |||
74 | #define WL12XX_MAX_RATE_POLICIES 16 | 68 | #define WL12XX_MAX_RATE_POLICIES 16 |
75 | 69 | ||
76 | /* Defined by FW as 0. Will not be freed or allocated. */ | 70 | /* Defined by FW as 0. Will not be freed or allocated. */ |
@@ -247,7 +241,7 @@ enum wl12xx_flags { | |||
247 | WL1271_FLAG_RECOVERY_IN_PROGRESS, | 241 | WL1271_FLAG_RECOVERY_IN_PROGRESS, |
248 | WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, | 242 | WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, |
249 | WL1271_FLAG_INTENDED_FW_RECOVERY, | 243 | WL1271_FLAG_INTENDED_FW_RECOVERY, |
250 | WL1271_FLAG_SDIO_FAILED, | 244 | WL1271_FLAG_IO_FAILED, |
251 | }; | 245 | }; |
252 | 246 | ||
253 | enum wl12xx_vif_flags { | 247 | enum wl12xx_vif_flags { |
@@ -369,7 +363,7 @@ struct wl12xx_vif { | |||
369 | int channel; | 363 | int channel; |
370 | enum nl80211_channel_type channel_type; | 364 | enum nl80211_channel_type channel_type; |
371 | 365 | ||
372 | u32 bitrate_masks[IEEE80211_NUM_BANDS]; | 366 | u32 bitrate_masks[WLCORE_NUM_BANDS]; |
373 | u32 basic_rate_set; | 367 | u32 basic_rate_set; |
374 | 368 | ||
375 | /* | 369 | /* |
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 1f74a77d040d..e7fd4938f9bc 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c | |||
@@ -535,9 +535,10 @@ static int nfcwilink_probe(struct platform_device *pdev) | |||
535 | drv->pdev = pdev; | 535 | drv->pdev = pdev; |
536 | 536 | ||
537 | protocols = NFC_PROTO_JEWEL_MASK | 537 | protocols = NFC_PROTO_JEWEL_MASK |
538 | | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK | 538 | | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK |
539 | | NFC_PROTO_ISO14443_MASK | 539 | | NFC_PROTO_ISO14443_MASK |
540 | | NFC_PROTO_NFC_DEP_MASK; | 540 | | NFC_PROTO_ISO14443_B_MASK |
541 | | NFC_PROTO_NFC_DEP_MASK; | ||
541 | 542 | ||
542 | drv->ndev = nci_allocate_device(&nfcwilink_ops, | 543 | drv->ndev = nci_allocate_device(&nfcwilink_ops, |
543 | protocols, | 544 | protocols, |
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 9ac829e22e73..d606f52fec84 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -38,9 +38,44 @@ | |||
38 | #define SCM_VENDOR_ID 0x4E6 | 38 | #define SCM_VENDOR_ID 0x4E6 |
39 | #define SCL3711_PRODUCT_ID 0x5591 | 39 | #define SCL3711_PRODUCT_ID 0x5591 |
40 | 40 | ||
41 | #define SONY_VENDOR_ID 0x054c | ||
42 | #define PASORI_PRODUCT_ID 0x02e1 | ||
43 | |||
44 | #define PN533_QUIRKS_TYPE_A BIT(0) | ||
45 | #define PN533_QUIRKS_TYPE_F BIT(1) | ||
46 | #define PN533_QUIRKS_DEP BIT(2) | ||
47 | #define PN533_QUIRKS_RAW_EXCHANGE BIT(3) | ||
48 | |||
49 | #define PN533_DEVICE_STD 0x1 | ||
50 | #define PN533_DEVICE_PASORI 0x2 | ||
51 | |||
52 | #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ | ||
53 | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ | ||
54 | NFC_PROTO_NFC_DEP_MASK |\ | ||
55 | NFC_PROTO_ISO14443_B_MASK) | ||
56 | |||
57 | #define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ | ||
58 | NFC_PROTO_MIFARE_MASK | \ | ||
59 | NFC_PROTO_FELICA_MASK | \ | ||
60 | NFC_PROTO_ISO14443_MASK | \ | ||
61 | NFC_PROTO_NFC_DEP_MASK) | ||
62 | |||
41 | static const struct usb_device_id pn533_table[] = { | 63 | static const struct usb_device_id pn533_table[] = { |
42 | { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) }, | 64 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, |
43 | { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) }, | 65 | .idVendor = PN533_VENDOR_ID, |
66 | .idProduct = PN533_PRODUCT_ID, | ||
67 | .driver_info = PN533_DEVICE_STD, | ||
68 | }, | ||
69 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
70 | .idVendor = SCM_VENDOR_ID, | ||
71 | .idProduct = SCL3711_PRODUCT_ID, | ||
72 | .driver_info = PN533_DEVICE_STD, | ||
73 | }, | ||
74 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
75 | .idVendor = SONY_VENDOR_ID, | ||
76 | .idProduct = PASORI_PRODUCT_ID, | ||
77 | .driver_info = PN533_DEVICE_PASORI, | ||
78 | }, | ||
44 | { } | 79 | { } |
45 | }; | 80 | }; |
46 | MODULE_DEVICE_TABLE(usb, pn533_table); | 81 | MODULE_DEVICE_TABLE(usb, pn533_table); |
@@ -72,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); | |||
72 | #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 | 107 | #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 |
73 | #define PN533_CMD_RF_CONFIGURATION 0x32 | 108 | #define PN533_CMD_RF_CONFIGURATION 0x32 |
74 | #define PN533_CMD_IN_DATA_EXCHANGE 0x40 | 109 | #define PN533_CMD_IN_DATA_EXCHANGE 0x40 |
110 | #define PN533_CMD_IN_COMM_THRU 0x42 | ||
75 | #define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A | 111 | #define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A |
76 | #define PN533_CMD_IN_ATR 0x50 | 112 | #define PN533_CMD_IN_ATR 0x50 |
77 | #define PN533_CMD_IN_RELEASE 0x52 | 113 | #define PN533_CMD_IN_RELEASE 0x52 |
@@ -109,6 +145,7 @@ struct pn533_fw_version { | |||
109 | /* PN533_CMD_RF_CONFIGURATION */ | 145 | /* PN533_CMD_RF_CONFIGURATION */ |
110 | #define PN533_CFGITEM_TIMING 0x02 | 146 | #define PN533_CFGITEM_TIMING 0x02 |
111 | #define PN533_CFGITEM_MAX_RETRIES 0x05 | 147 | #define PN533_CFGITEM_MAX_RETRIES 0x05 |
148 | #define PN533_CFGITEM_PASORI 0x82 | ||
112 | 149 | ||
113 | #define PN533_CONFIG_TIMING_102 0xb | 150 | #define PN533_CONFIG_TIMING_102 0xb |
114 | #define PN533_CONFIG_TIMING_204 0xc | 151 | #define PN533_CONFIG_TIMING_204 0xc |
@@ -344,6 +381,8 @@ struct pn533 { | |||
344 | u8 tgt_available_prots; | 381 | u8 tgt_available_prots; |
345 | u8 tgt_active_prot; | 382 | u8 tgt_active_prot; |
346 | u8 tgt_mode; | 383 | u8 tgt_mode; |
384 | |||
385 | u32 device_type; | ||
347 | }; | 386 | }; |
348 | 387 | ||
349 | struct pn533_frame { | 388 | struct pn533_frame { |
@@ -950,7 +989,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, | |||
950 | if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) | 989 | if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) |
951 | return -EPROTO; | 990 | return -EPROTO; |
952 | 991 | ||
953 | nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; | 992 | nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK; |
954 | 993 | ||
955 | return 0; | 994 | return 0; |
956 | } | 995 | } |
@@ -1057,7 +1096,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, | |||
1057 | if (im_protocols & NFC_PROTO_JEWEL_MASK) | 1096 | if (im_protocols & NFC_PROTO_JEWEL_MASK) |
1058 | pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); | 1097 | pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); |
1059 | 1098 | ||
1060 | if (im_protocols & NFC_PROTO_ISO14443_MASK) | 1099 | if (im_protocols & NFC_PROTO_ISO14443_B_MASK) |
1061 | pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); | 1100 | pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); |
1062 | 1101 | ||
1063 | if (tm_protocols) | 1102 | if (tm_protocols) |
@@ -1768,13 +1807,30 @@ static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb, | |||
1768 | } | 1807 | } |
1769 | 1808 | ||
1770 | if (target == true) { | 1809 | if (target == true) { |
1771 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); | 1810 | switch (dev->device_type) { |
1772 | out_frame = (struct pn533_frame *) skb->data; | 1811 | case PN533_DEVICE_PASORI: |
1812 | if (dev->tgt_active_prot == NFC_PROTO_FELICA) { | ||
1813 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); | ||
1814 | out_frame = (struct pn533_frame *) skb->data; | ||
1815 | pn533_tx_frame_init(out_frame, | ||
1816 | PN533_CMD_IN_COMM_THRU); | ||
1817 | |||
1818 | break; | ||
1819 | } | ||
1820 | |||
1821 | default: | ||
1822 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); | ||
1823 | out_frame = (struct pn533_frame *) skb->data; | ||
1824 | pn533_tx_frame_init(out_frame, | ||
1825 | PN533_CMD_IN_DATA_EXCHANGE); | ||
1826 | tg = 1; | ||
1827 | memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), | ||
1828 | &tg, sizeof(u8)); | ||
1829 | out_frame->datalen += sizeof(u8); | ||
1830 | |||
1831 | break; | ||
1832 | } | ||
1773 | 1833 | ||
1774 | pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE); | ||
1775 | tg = 1; | ||
1776 | memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8)); | ||
1777 | out_frame->datalen += sizeof(u8); | ||
1778 | } else { | 1834 | } else { |
1779 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); | 1835 | skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); |
1780 | out_frame = (struct pn533_frame *) skb->data; | 1836 | out_frame = (struct pn533_frame *) skb->data; |
@@ -2101,7 +2157,28 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, | |||
2101 | return rc; | 2157 | return rc; |
2102 | } | 2158 | } |
2103 | 2159 | ||
2104 | struct nfc_ops pn533_nfc_ops = { | 2160 | static int pn533_fw_reset(struct pn533 *dev) |
2161 | { | ||
2162 | int rc; | ||
2163 | u8 *params; | ||
2164 | |||
2165 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
2166 | |||
2167 | pn533_tx_frame_init(dev->out_frame, 0x18); | ||
2168 | |||
2169 | params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame); | ||
2170 | params[0] = 0x1; | ||
2171 | dev->out_frame->datalen += 1; | ||
2172 | |||
2173 | pn533_tx_frame_finish(dev->out_frame); | ||
2174 | |||
2175 | rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, | ||
2176 | dev->in_maxlen); | ||
2177 | |||
2178 | return rc; | ||
2179 | } | ||
2180 | |||
2181 | static struct nfc_ops pn533_nfc_ops = { | ||
2105 | .dev_up = NULL, | 2182 | .dev_up = NULL, |
2106 | .dev_down = NULL, | 2183 | .dev_down = NULL, |
2107 | .dep_link_up = pn533_dep_link_up, | 2184 | .dep_link_up = pn533_dep_link_up, |
@@ -2114,6 +2191,84 @@ struct nfc_ops pn533_nfc_ops = { | |||
2114 | .tm_send = pn533_tm_send, | 2191 | .tm_send = pn533_tm_send, |
2115 | }; | 2192 | }; |
2116 | 2193 | ||
2194 | static int pn533_setup(struct pn533 *dev) | ||
2195 | { | ||
2196 | struct pn533_config_max_retries max_retries; | ||
2197 | struct pn533_config_timing timing; | ||
2198 | u8 pasori_cfg[3] = {0x08, 0x01, 0x08}; | ||
2199 | int rc; | ||
2200 | |||
2201 | switch (dev->device_type) { | ||
2202 | case PN533_DEVICE_STD: | ||
2203 | max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; | ||
2204 | max_retries.mx_rty_psl = 2; | ||
2205 | max_retries.mx_rty_passive_act = | ||
2206 | PN533_CONFIG_MAX_RETRIES_NO_RETRY; | ||
2207 | |||
2208 | timing.rfu = PN533_CONFIG_TIMING_102; | ||
2209 | timing.atr_res_timeout = PN533_CONFIG_TIMING_204; | ||
2210 | timing.dep_timeout = PN533_CONFIG_TIMING_409; | ||
2211 | |||
2212 | break; | ||
2213 | |||
2214 | case PN533_DEVICE_PASORI: | ||
2215 | max_retries.mx_rty_atr = 0x2; | ||
2216 | max_retries.mx_rty_psl = 0x1; | ||
2217 | max_retries.mx_rty_passive_act = | ||
2218 | PN533_CONFIG_MAX_RETRIES_NO_RETRY; | ||
2219 | |||
2220 | timing.rfu = PN533_CONFIG_TIMING_102; | ||
2221 | timing.atr_res_timeout = PN533_CONFIG_TIMING_102; | ||
2222 | timing.dep_timeout = PN533_CONFIG_TIMING_204; | ||
2223 | |||
2224 | break; | ||
2225 | |||
2226 | default: | ||
2227 | nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", | ||
2228 | dev->device_type); | ||
2229 | return -EINVAL; | ||
2230 | } | ||
2231 | |||
2232 | rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, | ||
2233 | (u8 *)&max_retries, sizeof(max_retries)); | ||
2234 | if (rc) { | ||
2235 | nfc_dev_err(&dev->interface->dev, | ||
2236 | "Error on setting MAX_RETRIES config"); | ||
2237 | return rc; | ||
2238 | } | ||
2239 | |||
2240 | |||
2241 | rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, | ||
2242 | (u8 *)&timing, sizeof(timing)); | ||
2243 | if (rc) { | ||
2244 | nfc_dev_err(&dev->interface->dev, | ||
2245 | "Error on setting RF timings"); | ||
2246 | return rc; | ||
2247 | } | ||
2248 | |||
2249 | switch (dev->device_type) { | ||
2250 | case PN533_DEVICE_STD: | ||
2251 | break; | ||
2252 | |||
2253 | case PN533_DEVICE_PASORI: | ||
2254 | pn533_fw_reset(dev); | ||
2255 | |||
2256 | rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, | ||
2257 | pasori_cfg, 3); | ||
2258 | if (rc) { | ||
2259 | nfc_dev_err(&dev->interface->dev, | ||
2260 | "Error while settings PASORI config"); | ||
2261 | return rc; | ||
2262 | } | ||
2263 | |||
2264 | pn533_fw_reset(dev); | ||
2265 | |||
2266 | break; | ||
2267 | } | ||
2268 | |||
2269 | return 0; | ||
2270 | } | ||
2271 | |||
2117 | static int pn533_probe(struct usb_interface *interface, | 2272 | static int pn533_probe(struct usb_interface *interface, |
2118 | const struct usb_device_id *id) | 2273 | const struct usb_device_id *id) |
2119 | { | 2274 | { |
@@ -2121,8 +2276,6 @@ static int pn533_probe(struct usb_interface *interface, | |||
2121 | struct pn533 *dev; | 2276 | struct pn533 *dev; |
2122 | struct usb_host_interface *iface_desc; | 2277 | struct usb_host_interface *iface_desc; |
2123 | struct usb_endpoint_descriptor *endpoint; | 2278 | struct usb_endpoint_descriptor *endpoint; |
2124 | struct pn533_config_max_retries max_retries; | ||
2125 | struct pn533_config_timing timing; | ||
2126 | int in_endpoint = 0; | 2279 | int in_endpoint = 0; |
2127 | int out_endpoint = 0; | 2280 | int out_endpoint = 0; |
2128 | int rc = -ENOMEM; | 2281 | int rc = -ENOMEM; |
@@ -2208,10 +2361,22 @@ static int pn533_probe(struct usb_interface *interface, | |||
2208 | nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now" | 2361 | nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now" |
2209 | " attached", fw_ver->ver, fw_ver->rev); | 2362 | " attached", fw_ver->ver, fw_ver->rev); |
2210 | 2363 | ||
2211 | protocols = NFC_PROTO_JEWEL_MASK | 2364 | dev->device_type = id->driver_info; |
2212 | | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK | 2365 | switch (dev->device_type) { |
2213 | | NFC_PROTO_ISO14443_MASK | 2366 | case PN533_DEVICE_STD: |
2214 | | NFC_PROTO_NFC_DEP_MASK; | 2367 | protocols = PN533_ALL_PROTOCOLS; |
2368 | break; | ||
2369 | |||
2370 | case PN533_DEVICE_PASORI: | ||
2371 | protocols = PN533_NO_TYPE_B_PROTOCOLS; | ||
2372 | break; | ||
2373 | |||
2374 | default: | ||
2375 | nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", | ||
2376 | dev->device_type); | ||
2377 | rc = -EINVAL; | ||
2378 | goto destroy_wq; | ||
2379 | } | ||
2215 | 2380 | ||
2216 | dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, | 2381 | dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, |
2217 | PN533_CMD_DATAEXCH_HEAD_LEN, | 2382 | PN533_CMD_DATAEXCH_HEAD_LEN, |
@@ -2226,30 +2391,9 @@ static int pn533_probe(struct usb_interface *interface, | |||
2226 | if (rc) | 2391 | if (rc) |
2227 | goto free_nfc_dev; | 2392 | goto free_nfc_dev; |
2228 | 2393 | ||
2229 | max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; | 2394 | rc = pn533_setup(dev); |
2230 | max_retries.mx_rty_psl = 2; | 2395 | if (rc) |
2231 | max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY; | ||
2232 | |||
2233 | rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, | ||
2234 | (u8 *) &max_retries, sizeof(max_retries)); | ||
2235 | |||
2236 | if (rc) { | ||
2237 | nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES" | ||
2238 | " config"); | ||
2239 | goto unregister_nfc_dev; | ||
2240 | } | ||
2241 | |||
2242 | timing.rfu = PN533_CONFIG_TIMING_102; | ||
2243 | timing.atr_res_timeout = PN533_CONFIG_TIMING_204; | ||
2244 | timing.dep_timeout = PN533_CONFIG_TIMING_409; | ||
2245 | |||
2246 | rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, | ||
2247 | (u8 *) &timing, sizeof(timing)); | ||
2248 | if (rc) { | ||
2249 | nfc_dev_err(&dev->interface->dev, | ||
2250 | "Error on setting RF timings"); | ||
2251 | goto unregister_nfc_dev; | 2396 | goto unregister_nfc_dev; |
2252 | } | ||
2253 | 2397 | ||
2254 | return 0; | 2398 | return 0; |
2255 | 2399 | ||
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index 457eac35dc74..aa71807189ba 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c | |||
@@ -108,16 +108,22 @@ enum pn544_state { | |||
108 | 108 | ||
109 | #define PN544_NFC_WI_MGMT_GATE 0xA1 | 109 | #define PN544_NFC_WI_MGMT_GATE 0xA1 |
110 | 110 | ||
111 | static u8 pn544_custom_gates[] = { | 111 | static struct nfc_hci_gate pn544_gates[] = { |
112 | PN544_SYS_MGMT_GATE, | 112 | {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE}, |
113 | PN544_SWP_MGMT_GATE, | 113 | {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, |
114 | PN544_POLLING_LOOP_MGMT_GATE, | 114 | {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, |
115 | PN544_NFC_WI_MGMT_GATE, | 115 | {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE}, |
116 | PN544_RF_READER_F_GATE, | 116 | {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, |
117 | PN544_RF_READER_JEWEL_GATE, | 117 | {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, |
118 | PN544_RF_READER_ISO15693_GATE, | 118 | {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE}, |
119 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | 119 | {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, |
120 | PN544_RF_READER_NFCIP1_TARGET_GATE | 120 | {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, |
121 | {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | ||
122 | {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, | ||
123 | {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE}, | ||
124 | {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, | ||
125 | {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE}, | ||
126 | {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE} | ||
121 | }; | 127 | }; |
122 | 128 | ||
123 | /* Largest headroom needed for outgoing custom commands */ | 129 | /* Largest headroom needed for outgoing custom commands */ |
@@ -377,6 +383,9 @@ static int pn544_hci_open(struct nfc_shdlc *shdlc) | |||
377 | 383 | ||
378 | r = pn544_hci_enable(info, HCI_MODE); | 384 | r = pn544_hci_enable(info, HCI_MODE); |
379 | 385 | ||
386 | if (r == 0) | ||
387 | info->state = PN544_ST_READY; | ||
388 | |||
380 | out: | 389 | out: |
381 | mutex_unlock(&info->info_lock); | 390 | mutex_unlock(&info->info_lock); |
382 | return r; | 391 | return r; |
@@ -393,6 +402,8 @@ static void pn544_hci_close(struct nfc_shdlc *shdlc) | |||
393 | 402 | ||
394 | pn544_hci_disable(info); | 403 | pn544_hci_disable(info); |
395 | 404 | ||
405 | info->state = PN544_ST_COLD; | ||
406 | |||
396 | out: | 407 | out: |
397 | mutex_unlock(&info->info_lock); | 408 | mutex_unlock(&info->info_lock); |
398 | } | 409 | } |
@@ -844,10 +855,9 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, | |||
844 | goto err_rti; | 855 | goto err_rti; |
845 | } | 856 | } |
846 | 857 | ||
847 | init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); | 858 | init_data.gate_count = ARRAY_SIZE(pn544_gates); |
848 | 859 | ||
849 | memcpy(init_data.gates, pn544_custom_gates, | 860 | memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates)); |
850 | ARRAY_SIZE(pn544_custom_gates)); | ||
851 | 861 | ||
852 | /* | 862 | /* |
853 | * TODO: Session id must include the driver name + some bus addr | 863 | * TODO: Session id must include the driver name + some bus addr |
@@ -859,6 +869,7 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, | |||
859 | NFC_PROTO_MIFARE_MASK | | 869 | NFC_PROTO_MIFARE_MASK | |
860 | NFC_PROTO_FELICA_MASK | | 870 | NFC_PROTO_FELICA_MASK | |
861 | NFC_PROTO_ISO14443_MASK | | 871 | NFC_PROTO_ISO14443_MASK | |
872 | NFC_PROTO_ISO14443_B_MASK | | ||
862 | NFC_PROTO_NFC_DEP_MASK; | 873 | NFC_PROTO_NFC_DEP_MASK; |
863 | 874 | ||
864 | info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, | 875 | info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, |
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 12334f9190cb..03b2f30d2ace 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h | |||
@@ -137,6 +137,36 @@ struct bcma_host_ops { | |||
137 | 137 | ||
138 | #define BCMA_MAX_NR_CORES 16 | 138 | #define BCMA_MAX_NR_CORES 16 |
139 | 139 | ||
140 | /* Chip IDs of PCIe devices */ | ||
141 | #define BCMA_CHIP_ID_BCM4313 0x4313 | ||
142 | #define BCMA_CHIP_ID_BCM43224 43224 | ||
143 | #define BCMA_PKG_ID_BCM43224_FAB_CSM 0x8 | ||
144 | #define BCMA_PKG_ID_BCM43224_FAB_SMIC 0xa | ||
145 | #define BCMA_CHIP_ID_BCM43225 43225 | ||
146 | #define BCMA_CHIP_ID_BCM43227 43227 | ||
147 | #define BCMA_CHIP_ID_BCM43228 43228 | ||
148 | #define BCMA_CHIP_ID_BCM43421 43421 | ||
149 | #define BCMA_CHIP_ID_BCM43428 43428 | ||
150 | #define BCMA_CHIP_ID_BCM43431 43431 | ||
151 | #define BCMA_CHIP_ID_BCM43460 43460 | ||
152 | #define BCMA_CHIP_ID_BCM4331 0x4331 | ||
153 | #define BCMA_CHIP_ID_BCM6362 0x6362 | ||
154 | #define BCMA_CHIP_ID_BCM4360 0x4360 | ||
155 | #define BCMA_CHIP_ID_BCM4352 0x4352 | ||
156 | |||
157 | /* Chip IDs of SoCs */ | ||
158 | #define BCMA_CHIP_ID_BCM4706 0x5300 | ||
159 | #define BCMA_CHIP_ID_BCM4716 0x4716 | ||
160 | #define BCMA_PKG_ID_BCM4716 8 | ||
161 | #define BCMA_PKG_ID_BCM4717 9 | ||
162 | #define BCMA_PKG_ID_BCM4718 10 | ||
163 | #define BCMA_CHIP_ID_BCM47162 47162 | ||
164 | #define BCMA_CHIP_ID_BCM4748 0x4748 | ||
165 | #define BCMA_CHIP_ID_BCM4749 0x4749 | ||
166 | #define BCMA_CHIP_ID_BCM5356 0x5356 | ||
167 | #define BCMA_CHIP_ID_BCM5357 0x5357 | ||
168 | #define BCMA_CHIP_ID_BCM53572 53572 | ||
169 | |||
140 | struct bcma_device { | 170 | struct bcma_device { |
141 | struct bcma_bus *bus; | 171 | struct bcma_bus *bus; |
142 | struct bcma_device_id id; | 172 | struct bcma_device_id id; |
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 8bbfe31fbac8..fbd0d49dc4d2 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h | |||
@@ -88,6 +88,11 @@ | |||
88 | #define BCMA_CC_CHIPST_4313_OTP_PRESENT 2 | 88 | #define BCMA_CC_CHIPST_4313_OTP_PRESENT 2 |
89 | #define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2 | 89 | #define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2 |
90 | #define BCMA_CC_CHIPST_4331_OTP_PRESENT 4 | 90 | #define BCMA_CC_CHIPST_4331_OTP_PRESENT 4 |
91 | #define BCMA_CC_CHIPST_4706_PKG_OPTION BIT(0) /* 0: full-featured package 1: low-cost package */ | ||
92 | #define BCMA_CC_CHIPST_4706_SFLASH_PRESENT BIT(1) /* 0: parallel, 1: serial flash is present */ | ||
93 | #define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ | ||
94 | #define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */ | ||
95 | #define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */ | ||
91 | #define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ | 96 | #define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ |
92 | #define BCMA_CC_JCMD_START 0x80000000 | 97 | #define BCMA_CC_JCMD_START 0x80000000 |
93 | #define BCMA_CC_JCMD_BUSY 0x80000000 | 98 | #define BCMA_CC_JCMD_BUSY 0x80000000 |
@@ -280,6 +285,15 @@ | |||
280 | 285 | ||
281 | /* 4706 PMU */ | 286 | /* 4706 PMU */ |
282 | #define BCMA_CC_PMU4706_MAINPLL_PLL0 0 | 287 | #define BCMA_CC_PMU4706_MAINPLL_PLL0 0 |
288 | #define BCMA_CC_PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ | ||
289 | #define BCMA_CC_PMU6_4706_PROC_P2DIV_MASK 0x000f0000 | ||
290 | #define BCMA_CC_PMU6_4706_PROC_P2DIV_SHIFT 16 | ||
291 | #define BCMA_CC_PMU6_4706_PROC_P1DIV_MASK 0x0000f000 | ||
292 | #define BCMA_CC_PMU6_4706_PROC_P1DIV_SHIFT 12 | ||
293 | #define BCMA_CC_PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 | ||
294 | #define BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT 3 | ||
295 | #define BCMA_CC_PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 | ||
296 | #define BCMA_CC_PMU6_4706_PROC_NDIV_MODE_SHIFT 0 | ||
283 | 297 | ||
284 | /* ALP clock on pre-PMU chips */ | 298 | /* ALP clock on pre-PMU chips */ |
285 | #define BCMA_CC_PMU_ALP_CLOCK 20000000 | 299 | #define BCMA_CC_PMU_ALP_CLOCK 20000000 |
@@ -308,6 +322,19 @@ | |||
308 | #define BCMA_CC_PPL_PCHI_OFF 5 | 322 | #define BCMA_CC_PPL_PCHI_OFF 5 |
309 | #define BCMA_CC_PPL_PCHI_MASK 0x0000003f | 323 | #define BCMA_CC_PPL_PCHI_MASK 0x0000003f |
310 | 324 | ||
325 | #define BCMA_CC_PMU_PLL_CTL0 0 | ||
326 | #define BCMA_CC_PMU_PLL_CTL1 1 | ||
327 | #define BCMA_CC_PMU_PLL_CTL2 2 | ||
328 | #define BCMA_CC_PMU_PLL_CTL3 3 | ||
329 | #define BCMA_CC_PMU_PLL_CTL4 4 | ||
330 | #define BCMA_CC_PMU_PLL_CTL5 5 | ||
331 | |||
332 | #define BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 | ||
333 | #define BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT 20 | ||
334 | |||
335 | #define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 | ||
336 | #define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 | ||
337 | |||
311 | /* BCM4331 ChipControl numbers. */ | 338 | /* BCM4331 ChipControl numbers. */ |
312 | #define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */ | 339 | #define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */ |
313 | #define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */ | 340 | #define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */ |
@@ -321,9 +348,18 @@ | |||
321 | #define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */ | 348 | #define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */ |
322 | #define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */ | 349 | #define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */ |
323 | #define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */ | 350 | #define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */ |
351 | #define BCMA_CHIPCTL_4331_EXTPA_EN2 BIT(12) /* 0 ext pa disable, 1 ext pa enabled */ | ||
324 | #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */ | 352 | #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */ |
325 | #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */ | 353 | #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */ |
326 | 354 | ||
355 | /* 43224 chip-specific ChipControl register bits */ | ||
356 | #define BCMA_CCTRL_43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ | ||
357 | #define BCMA_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ | ||
358 | #define BCMA_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ | ||
359 | |||
360 | /* 4313 Chip specific ChipControl register bits */ | ||
361 | #define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ | ||
362 | |||
327 | /* Data for the PMU, if available. | 363 | /* Data for the PMU, if available. |
328 | * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) | 364 | * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) |
329 | */ | 365 | */ |
@@ -411,5 +447,6 @@ extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | |||
411 | u32 offset, u32 mask, u32 set); | 447 | u32 offset, u32 mask, u32 set); |
412 | extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, | 448 | extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, |
413 | u32 offset, u32 mask, u32 set); | 449 | u32 offset, u32 mask, u32 set); |
450 | extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid); | ||
414 | 451 | ||
415 | #endif /* LINUX_BCMA_DRIVER_CC_H_ */ | 452 | #endif /* LINUX_BCMA_DRIVER_CC_H_ */ |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 318fc1f705b1..e02fc682bb68 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #define IEEE80211_FCTL_MOREDATA 0x2000 | 47 | #define IEEE80211_FCTL_MOREDATA 0x2000 |
48 | #define IEEE80211_FCTL_PROTECTED 0x4000 | 48 | #define IEEE80211_FCTL_PROTECTED 0x4000 |
49 | #define IEEE80211_FCTL_ORDER 0x8000 | 49 | #define IEEE80211_FCTL_ORDER 0x8000 |
50 | #define IEEE80211_FCTL_CTL_EXT 0x0f00 | ||
50 | 51 | ||
51 | #define IEEE80211_SCTL_FRAG 0x000F | 52 | #define IEEE80211_SCTL_FRAG 0x000F |
52 | #define IEEE80211_SCTL_SEQ 0xFFF0 | 53 | #define IEEE80211_SCTL_SEQ 0xFFF0 |
@@ -54,6 +55,7 @@ | |||
54 | #define IEEE80211_FTYPE_MGMT 0x0000 | 55 | #define IEEE80211_FTYPE_MGMT 0x0000 |
55 | #define IEEE80211_FTYPE_CTL 0x0004 | 56 | #define IEEE80211_FTYPE_CTL 0x0004 |
56 | #define IEEE80211_FTYPE_DATA 0x0008 | 57 | #define IEEE80211_FTYPE_DATA 0x0008 |
58 | #define IEEE80211_FTYPE_EXT 0x000c | ||
57 | 59 | ||
58 | /* management */ | 60 | /* management */ |
59 | #define IEEE80211_STYPE_ASSOC_REQ 0x0000 | 61 | #define IEEE80211_STYPE_ASSOC_REQ 0x0000 |
@@ -70,6 +72,7 @@ | |||
70 | #define IEEE80211_STYPE_ACTION 0x00D0 | 72 | #define IEEE80211_STYPE_ACTION 0x00D0 |
71 | 73 | ||
72 | /* control */ | 74 | /* control */ |
75 | #define IEEE80211_STYPE_CTL_EXT 0x0060 | ||
73 | #define IEEE80211_STYPE_BACK_REQ 0x0080 | 76 | #define IEEE80211_STYPE_BACK_REQ 0x0080 |
74 | #define IEEE80211_STYPE_BACK 0x0090 | 77 | #define IEEE80211_STYPE_BACK 0x0090 |
75 | #define IEEE80211_STYPE_PSPOLL 0x00A0 | 78 | #define IEEE80211_STYPE_PSPOLL 0x00A0 |
@@ -97,6 +100,18 @@ | |||
97 | #define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 | 100 | #define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 |
98 | #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 | 101 | #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 |
99 | 102 | ||
103 | /* extension, added by 802.11ad */ | ||
104 | #define IEEE80211_STYPE_DMG_BEACON 0x0000 | ||
105 | |||
106 | /* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */ | ||
107 | #define IEEE80211_CTL_EXT_POLL 0x2000 | ||
108 | #define IEEE80211_CTL_EXT_SPR 0x3000 | ||
109 | #define IEEE80211_CTL_EXT_GRANT 0x4000 | ||
110 | #define IEEE80211_CTL_EXT_DMG_CTS 0x5000 | ||
111 | #define IEEE80211_CTL_EXT_DMG_DTS 0x6000 | ||
112 | #define IEEE80211_CTL_EXT_SSW 0x8000 | ||
113 | #define IEEE80211_CTL_EXT_SSW_FBACK 0x9000 | ||
114 | #define IEEE80211_CTL_EXT_SSW_ACK 0xa000 | ||
100 | 115 | ||
101 | /* miscellaneous IEEE 802.11 constants */ | 116 | /* miscellaneous IEEE 802.11 constants */ |
102 | #define IEEE80211_MAX_FRAG_THRESHOLD 2352 | 117 | #define IEEE80211_MAX_FRAG_THRESHOLD 2352 |
@@ -1092,6 +1107,73 @@ struct ieee80211_ht_operation { | |||
1092 | #define WLAN_HT_SMPS_CONTROL_STATIC 1 | 1107 | #define WLAN_HT_SMPS_CONTROL_STATIC 1 |
1093 | #define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 | 1108 | #define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 |
1094 | 1109 | ||
1110 | #define VHT_MCS_SUPPORTED_SET_SIZE 8 | ||
1111 | |||
1112 | struct ieee80211_vht_capabilities { | ||
1113 | __le32 vht_capabilities_info; | ||
1114 | u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE]; | ||
1115 | } __packed; | ||
1116 | |||
1117 | struct ieee80211_vht_operation { | ||
1118 | u8 vht_op_info_chwidth; | ||
1119 | u8 vht_op_info_chan_center_freq_seg1_idx; | ||
1120 | u8 vht_op_info_chan_center_freq_seg2_idx; | ||
1121 | __le16 vht_basic_mcs_set; | ||
1122 | } __packed; | ||
1123 | |||
1124 | /** | ||
1125 | * struct ieee80211_vht_mcs_info - VHT MCS information | ||
1126 | * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams | ||
1127 | * @rx_highest: Indicates highest long GI VHT PPDU data rate | ||
1128 | * STA can receive. Rate expressed in units of 1 Mbps. | ||
1129 | * If this field is 0 this value should not be used to | ||
1130 | * consider the highest RX data rate supported. | ||
1131 | * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams | ||
1132 | * @tx_highest: Indicates highest long GI VHT PPDU data rate | ||
1133 | * STA can transmit. Rate expressed in units of 1 Mbps. | ||
1134 | * If this field is 0 this value should not be used to | ||
1135 | * consider the highest TX data rate supported. | ||
1136 | */ | ||
1137 | struct ieee80211_vht_mcs_info { | ||
1138 | __le16 rx_mcs_map; | ||
1139 | __le16 rx_highest; | ||
1140 | __le16 tx_mcs_map; | ||
1141 | __le16 tx_highest; | ||
1142 | } __packed; | ||
1143 | |||
1144 | #define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0 | ||
1145 | #define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1 | ||
1146 | #define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2 | ||
1147 | #define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 | ||
1148 | |||
1149 | /* 802.11ac VHT Capabilities */ | ||
1150 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 | ||
1151 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 | ||
1152 | #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 | ||
1153 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 | ||
1154 | #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 | ||
1155 | #define IEEE80211_VHT_CAP_RXLDPC 0x00000010 | ||
1156 | #define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 | ||
1157 | #define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 | ||
1158 | #define IEEE80211_VHT_CAP_TXSTBC 0x00000080 | ||
1159 | #define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 | ||
1160 | #define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 | ||
1161 | #define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 | ||
1162 | #define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 | ||
1163 | #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 | ||
1164 | #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 | ||
1165 | #define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 | ||
1166 | #define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 | ||
1167 | #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 | ||
1168 | #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 | ||
1169 | #define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 | ||
1170 | #define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 | ||
1171 | #define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT 0x00800000 | ||
1172 | #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 | ||
1173 | #define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 | ||
1174 | #define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 | ||
1175 | #define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 | ||
1176 | |||
1095 | /* Authentication algorithms */ | 1177 | /* Authentication algorithms */ |
1096 | #define WLAN_AUTH_OPEN 0 | 1178 | #define WLAN_AUTH_OPEN 0 |
1097 | #define WLAN_AUTH_SHARED_KEY 1 | 1179 | #define WLAN_AUTH_SHARED_KEY 1 |
@@ -1124,6 +1206,21 @@ struct ieee80211_ht_operation { | |||
1124 | #define WLAN_CAPABILITY_QOS (1<<9) | 1206 | #define WLAN_CAPABILITY_QOS (1<<9) |
1125 | #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) | 1207 | #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) |
1126 | #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) | 1208 | #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) |
1209 | |||
1210 | /* DMG (60gHz) 802.11ad */ | ||
1211 | /* type - bits 0..1 */ | ||
1212 | #define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */ | ||
1213 | #define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */ | ||
1214 | #define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */ | ||
1215 | |||
1216 | #define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2) | ||
1217 | #define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3) | ||
1218 | #define WLAN_CAPABILITY_DMG_PRIVACY (1<<4) | ||
1219 | #define WLAN_CAPABILITY_DMG_ECPAC (1<<5) | ||
1220 | |||
1221 | #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8) | ||
1222 | #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12) | ||
1223 | |||
1127 | /* measurement */ | 1224 | /* measurement */ |
1128 | #define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0) | 1225 | #define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0) |
1129 | #define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1) | 1226 | #define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1) |
@@ -1133,7 +1230,6 @@ struct ieee80211_ht_operation { | |||
1133 | #define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1 | 1230 | #define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1 |
1134 | #define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2 | 1231 | #define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2 |
1135 | 1232 | ||
1136 | |||
1137 | /* 802.11g ERP information element */ | 1233 | /* 802.11g ERP information element */ |
1138 | #define WLAN_ERP_NON_ERP_PRESENT (1<<0) | 1234 | #define WLAN_ERP_NON_ERP_PRESENT (1<<0) |
1139 | #define WLAN_ERP_USE_PROTECTION (1<<1) | 1235 | #define WLAN_ERP_USE_PROTECTION (1<<1) |
@@ -1145,6 +1241,16 @@ enum { | |||
1145 | WLAN_ERP_PREAMBLE_LONG = 1, | 1241 | WLAN_ERP_PREAMBLE_LONG = 1, |
1146 | }; | 1242 | }; |
1147 | 1243 | ||
1244 | /* Band ID, 802.11ad #8.4.1.45 */ | ||
1245 | enum { | ||
1246 | IEEE80211_BANDID_TV_WS = 0, /* TV white spaces */ | ||
1247 | IEEE80211_BANDID_SUB1 = 1, /* Sub-1 GHz (excluding TV white spaces) */ | ||
1248 | IEEE80211_BANDID_2G = 2, /* 2.4 GHz */ | ||
1249 | IEEE80211_BANDID_3G = 3, /* 3.6 GHz */ | ||
1250 | IEEE80211_BANDID_5G = 4, /* 4.9 and 5 GHz */ | ||
1251 | IEEE80211_BANDID_60G = 5, /* 60 GHz */ | ||
1252 | }; | ||
1253 | |||
1148 | /* Status codes */ | 1254 | /* Status codes */ |
1149 | enum ieee80211_statuscode { | 1255 | enum ieee80211_statuscode { |
1150 | WLAN_STATUS_SUCCESS = 0, | 1256 | WLAN_STATUS_SUCCESS = 0, |
@@ -1196,6 +1302,17 @@ enum ieee80211_statuscode { | |||
1196 | WLAN_STATUS_ANTI_CLOG_REQUIRED = 76, | 1302 | WLAN_STATUS_ANTI_CLOG_REQUIRED = 76, |
1197 | WLAN_STATUS_FCG_NOT_SUPP = 78, | 1303 | WLAN_STATUS_FCG_NOT_SUPP = 78, |
1198 | WLAN_STATUS_STA_NO_TBTT = 78, | 1304 | WLAN_STATUS_STA_NO_TBTT = 78, |
1305 | /* 802.11ad */ | ||
1306 | WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES = 39, | ||
1307 | WLAN_STATUS_REJECTED_FOR_DELAY_PERIOD = 47, | ||
1308 | WLAN_STATUS_REJECT_WITH_SCHEDULE = 83, | ||
1309 | WLAN_STATUS_PENDING_ADMITTING_FST_SESSION = 86, | ||
1310 | WLAN_STATUS_PERFORMING_FST_NOW = 87, | ||
1311 | WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW = 88, | ||
1312 | WLAN_STATUS_REJECT_U_PID_SETTING = 89, | ||
1313 | WLAN_STATUS_REJECT_DSE_BAND = 96, | ||
1314 | WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, | ||
1315 | WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, | ||
1199 | }; | 1316 | }; |
1200 | 1317 | ||
1201 | 1318 | ||
@@ -1352,6 +1469,43 @@ enum ieee80211_eid { | |||
1352 | WLAN_EID_DSE_REGISTERED_LOCATION = 58, | 1469 | WLAN_EID_DSE_REGISTERED_LOCATION = 58, |
1353 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, | 1470 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, |
1354 | WLAN_EID_EXT_CHANSWITCH_ANN = 60, | 1471 | WLAN_EID_EXT_CHANSWITCH_ANN = 60, |
1472 | |||
1473 | WLAN_EID_VHT_CAPABILITY = 191, | ||
1474 | WLAN_EID_VHT_OPERATION = 192, | ||
1475 | |||
1476 | /* 802.11ad */ | ||
1477 | WLAN_EID_NON_TX_BSSID_CAP = 83, | ||
1478 | WLAN_EID_WAKEUP_SCHEDULE = 143, | ||
1479 | WLAN_EID_EXT_SCHEDULE = 144, | ||
1480 | WLAN_EID_STA_AVAILABILITY = 145, | ||
1481 | WLAN_EID_DMG_TSPEC = 146, | ||
1482 | WLAN_EID_DMG_AT = 147, | ||
1483 | WLAN_EID_DMG_CAP = 148, | ||
1484 | WLAN_EID_DMG_OPERATION = 151, | ||
1485 | WLAN_EID_DMG_BSS_PARAM_CHANGE = 152, | ||
1486 | WLAN_EID_DMG_BEAM_REFINEMENT = 153, | ||
1487 | WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154, | ||
1488 | WLAN_EID_AWAKE_WINDOW = 157, | ||
1489 | WLAN_EID_MULTI_BAND = 158, | ||
1490 | WLAN_EID_ADDBA_EXT = 159, | ||
1491 | WLAN_EID_NEXT_PCP_LIST = 160, | ||
1492 | WLAN_EID_PCP_HANDOVER = 161, | ||
1493 | WLAN_EID_DMG_LINK_MARGIN = 162, | ||
1494 | WLAN_EID_SWITCHING_STREAM = 163, | ||
1495 | WLAN_EID_SESSION_TRANSITION = 164, | ||
1496 | WLAN_EID_DYN_TONE_PAIRING_REPORT = 165, | ||
1497 | WLAN_EID_CLUSTER_REPORT = 166, | ||
1498 | WLAN_EID_RELAY_CAP = 167, | ||
1499 | WLAN_EID_RELAY_XFER_PARAM_SET = 168, | ||
1500 | WLAN_EID_BEAM_LINK_MAINT = 169, | ||
1501 | WLAN_EID_MULTIPLE_MAC_ADDR = 170, | ||
1502 | WLAN_EID_U_PID = 171, | ||
1503 | WLAN_EID_DMG_LINK_ADAPT_ACK = 172, | ||
1504 | WLAN_EID_QUIET_PERIOD_REQ = 175, | ||
1505 | WLAN_EID_QUIET_PERIOD_RESP = 177, | ||
1506 | WLAN_EID_EPAC_POLICY = 182, | ||
1507 | WLAN_EID_CLISTER_TIME_OFF = 183, | ||
1508 | WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190, | ||
1355 | }; | 1509 | }; |
1356 | 1510 | ||
1357 | /* Action category code */ | 1511 | /* Action category code */ |
@@ -1368,7 +1522,10 @@ enum ieee80211_category { | |||
1368 | WLAN_CATEGORY_MESH_ACTION = 13, | 1522 | WLAN_CATEGORY_MESH_ACTION = 13, |
1369 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, | 1523 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, |
1370 | WLAN_CATEGORY_SELF_PROTECTED = 15, | 1524 | WLAN_CATEGORY_SELF_PROTECTED = 15, |
1525 | WLAN_CATEGORY_DMG = 16, | ||
1371 | WLAN_CATEGORY_WMM = 17, | 1526 | WLAN_CATEGORY_WMM = 17, |
1527 | WLAN_CATEGORY_FST = 18, | ||
1528 | WLAN_CATEGORY_UNPROT_DMG = 20, | ||
1372 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, | 1529 | WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, |
1373 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, | 1530 | WLAN_CATEGORY_VENDOR_SPECIFIC = 127, |
1374 | }; | 1531 | }; |
@@ -1616,6 +1773,7 @@ enum ieee80211_sa_query_action { | |||
1616 | #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 | 1773 | #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 |
1617 | #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 | 1774 | #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 |
1618 | #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 | 1775 | #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 |
1776 | #define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 | ||
1619 | 1777 | ||
1620 | #define WLAN_CIPHER_SUITE_SMS4 0x00147201 | 1778 | #define WLAN_CIPHER_SUITE_SMS4 0x00147201 |
1621 | 1779 | ||
diff --git a/include/linux/nfc.h b/include/linux/nfc.h index f4e6dd915b1c..6189f27e305b 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h | |||
@@ -136,8 +136,9 @@ enum nfc_attrs { | |||
136 | #define NFC_PROTO_FELICA 3 | 136 | #define NFC_PROTO_FELICA 3 |
137 | #define NFC_PROTO_ISO14443 4 | 137 | #define NFC_PROTO_ISO14443 4 |
138 | #define NFC_PROTO_NFC_DEP 5 | 138 | #define NFC_PROTO_NFC_DEP 5 |
139 | #define NFC_PROTO_ISO14443_B 6 | ||
139 | 140 | ||
140 | #define NFC_PROTO_MAX 6 | 141 | #define NFC_PROTO_MAX 7 |
141 | 142 | ||
142 | /* NFC communication modes */ | 143 | /* NFC communication modes */ |
143 | #define NFC_COMM_ACTIVE 0 | 144 | #define NFC_COMM_ACTIVE 0 |
@@ -149,11 +150,12 @@ enum nfc_attrs { | |||
149 | #define NFC_RF_NONE 2 | 150 | #define NFC_RF_NONE 2 |
150 | 151 | ||
151 | /* NFC protocols masks used in bitsets */ | 152 | /* NFC protocols masks used in bitsets */ |
152 | #define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) | 153 | #define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) |
153 | #define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) | 154 | #define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) |
154 | #define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) | 155 | #define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) |
155 | #define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) | 156 | #define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) |
156 | #define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) | 157 | #define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) |
158 | #define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B) | ||
157 | 159 | ||
158 | struct sockaddr_nfc { | 160 | struct sockaddr_nfc { |
159 | sa_family_t sa_family; | 161 | sa_family_t sa_family; |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c0fc5d277338..db961a59247f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -1638,12 +1638,20 @@ struct nl80211_sta_flag_update { | |||
1638 | * | 1638 | * |
1639 | * These attribute types are used with %NL80211_STA_INFO_TXRATE | 1639 | * These attribute types are used with %NL80211_STA_INFO_TXRATE |
1640 | * when getting information about the bitrate of a station. | 1640 | * when getting information about the bitrate of a station. |
1641 | * There are 2 attributes for bitrate, a legacy one that represents | ||
1642 | * a 16-bit value, and new one that represents a 32-bit value. | ||
1643 | * If the rate value fits into 16 bit, both attributes are reported | ||
1644 | * with the same value. If the rate is too high to fit into 16 bits | ||
1645 | * (>6.5535Gbps) only 32-bit attribute is included. | ||
1646 | * User space tools encouraged to use the 32-bit attribute and fall | ||
1647 | * back to the 16-bit one for compatibility with older kernels. | ||
1641 | * | 1648 | * |
1642 | * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved | 1649 | * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved |
1643 | * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) | 1650 | * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) |
1644 | * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) | 1651 | * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) |
1645 | * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate | 1652 | * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate |
1646 | * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval | 1653 | * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval |
1654 | * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) | ||
1647 | * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined | 1655 | * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined |
1648 | * @__NL80211_RATE_INFO_AFTER_LAST: internal use | 1656 | * @__NL80211_RATE_INFO_AFTER_LAST: internal use |
1649 | */ | 1657 | */ |
@@ -1653,6 +1661,7 @@ enum nl80211_rate_info { | |||
1653 | NL80211_RATE_INFO_MCS, | 1661 | NL80211_RATE_INFO_MCS, |
1654 | NL80211_RATE_INFO_40_MHZ_WIDTH, | 1662 | NL80211_RATE_INFO_40_MHZ_WIDTH, |
1655 | NL80211_RATE_INFO_SHORT_GI, | 1663 | NL80211_RATE_INFO_SHORT_GI, |
1664 | NL80211_RATE_INFO_BITRATE32, | ||
1656 | 1665 | ||
1657 | /* keep last */ | 1666 | /* keep last */ |
1658 | __NL80211_RATE_INFO_AFTER_LAST, | 1667 | __NL80211_RATE_INFO_AFTER_LAST, |
@@ -1813,6 +1822,9 @@ enum nl80211_mpath_info { | |||
1813 | * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE | 1822 | * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE |
1814 | * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n | 1823 | * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n |
1815 | * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n | 1824 | * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n |
1825 | * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as | ||
1826 | * defined in 802.11ac | ||
1827 | * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE | ||
1816 | * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined | 1828 | * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined |
1817 | * @__NL80211_BAND_ATTR_AFTER_LAST: internal use | 1829 | * @__NL80211_BAND_ATTR_AFTER_LAST: internal use |
1818 | */ | 1830 | */ |
@@ -1826,6 +1838,9 @@ enum nl80211_band_attr { | |||
1826 | NL80211_BAND_ATTR_HT_AMPDU_FACTOR, | 1838 | NL80211_BAND_ATTR_HT_AMPDU_FACTOR, |
1827 | NL80211_BAND_ATTR_HT_AMPDU_DENSITY, | 1839 | NL80211_BAND_ATTR_HT_AMPDU_DENSITY, |
1828 | 1840 | ||
1841 | NL80211_BAND_ATTR_VHT_MCS_SET, | ||
1842 | NL80211_BAND_ATTR_VHT_CAPA, | ||
1843 | |||
1829 | /* keep last */ | 1844 | /* keep last */ |
1830 | __NL80211_BAND_ATTR_AFTER_LAST, | 1845 | __NL80211_BAND_ATTR_AFTER_LAST, |
1831 | NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 | 1846 | NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 |
@@ -2539,10 +2554,12 @@ enum nl80211_tx_rate_attributes { | |||
2539 | * enum nl80211_band - Frequency band | 2554 | * enum nl80211_band - Frequency band |
2540 | * @NL80211_BAND_2GHZ: 2.4 GHz ISM band | 2555 | * @NL80211_BAND_2GHZ: 2.4 GHz ISM band |
2541 | * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) | 2556 | * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) |
2557 | * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) | ||
2542 | */ | 2558 | */ |
2543 | enum nl80211_band { | 2559 | enum nl80211_band { |
2544 | NL80211_BAND_2GHZ, | 2560 | NL80211_BAND_2GHZ, |
2545 | NL80211_BAND_5GHZ, | 2561 | NL80211_BAND_5GHZ, |
2562 | NL80211_BAND_60GHZ, | ||
2546 | }; | 2563 | }; |
2547 | 2564 | ||
2548 | /** | 2565 | /** |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 061c01957e54..51f67a9003a9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -70,11 +70,13 @@ | |||
70 | * | 70 | * |
71 | * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band | 71 | * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band |
72 | * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) | 72 | * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) |
73 | * @IEEE80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) | ||
73 | * @IEEE80211_NUM_BANDS: number of defined bands | 74 | * @IEEE80211_NUM_BANDS: number of defined bands |
74 | */ | 75 | */ |
75 | enum ieee80211_band { | 76 | enum ieee80211_band { |
76 | IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, | 77 | IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, |
77 | IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, | 78 | IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, |
79 | IEEE80211_BAND_60GHZ = NL80211_BAND_60GHZ, | ||
78 | 80 | ||
79 | /* keep last */ | 81 | /* keep last */ |
80 | IEEE80211_NUM_BANDS | 82 | IEEE80211_NUM_BANDS |
@@ -211,6 +213,22 @@ struct ieee80211_sta_ht_cap { | |||
211 | }; | 213 | }; |
212 | 214 | ||
213 | /** | 215 | /** |
216 | * struct ieee80211_sta_vht_cap - STA's VHT capabilities | ||
217 | * | ||
218 | * This structure describes most essential parameters needed | ||
219 | * to describe 802.11ac VHT capabilities for an STA. | ||
220 | * | ||
221 | * @vht_supported: is VHT supported by the STA | ||
222 | * @cap: VHT capabilities map as described in 802.11ac spec | ||
223 | * @vht_mcs: Supported VHT MCS rates | ||
224 | */ | ||
225 | struct ieee80211_sta_vht_cap { | ||
226 | bool vht_supported; | ||
227 | u32 cap; /* use IEEE80211_VHT_CAP_ */ | ||
228 | struct ieee80211_vht_mcs_info vht_mcs; | ||
229 | }; | ||
230 | |||
231 | /** | ||
214 | * struct ieee80211_supported_band - frequency band definition | 232 | * struct ieee80211_supported_band - frequency band definition |
215 | * | 233 | * |
216 | * This structure describes a frequency band a wiphy | 234 | * This structure describes a frequency band a wiphy |
@@ -233,6 +251,7 @@ struct ieee80211_supported_band { | |||
233 | int n_channels; | 251 | int n_channels; |
234 | int n_bitrates; | 252 | int n_bitrates; |
235 | struct ieee80211_sta_ht_cap ht_cap; | 253 | struct ieee80211_sta_ht_cap ht_cap; |
254 | struct ieee80211_sta_vht_cap vht_cap; | ||
236 | }; | 255 | }; |
237 | 256 | ||
238 | /* | 257 | /* |
@@ -561,11 +580,13 @@ enum station_info_flags { | |||
561 | * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled | 580 | * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled |
562 | * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission | 581 | * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission |
563 | * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval | 582 | * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval |
583 | * @RATE_INFO_FLAGS_60G: 60gHz MCS | ||
564 | */ | 584 | */ |
565 | enum rate_info_flags { | 585 | enum rate_info_flags { |
566 | RATE_INFO_FLAGS_MCS = 1<<0, | 586 | RATE_INFO_FLAGS_MCS = 1<<0, |
567 | RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, | 587 | RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, |
568 | RATE_INFO_FLAGS_SHORT_GI = 1<<2, | 588 | RATE_INFO_FLAGS_SHORT_GI = 1<<2, |
589 | RATE_INFO_FLAGS_60G = 1<<3, | ||
569 | }; | 590 | }; |
570 | 591 | ||
571 | /** | 592 | /** |
@@ -1482,9 +1503,8 @@ struct cfg80211_gtk_rekey_data { | |||
1482 | * interfaces are active this callback should reject the configuration. | 1503 | * interfaces are active this callback should reject the configuration. |
1483 | * If no interfaces are active or the device is down, the channel should | 1504 | * If no interfaces are active or the device is down, the channel should |
1484 | * be stored for when a monitor interface becomes active. | 1505 | * be stored for when a monitor interface becomes active. |
1485 | * @get_channel: Get the current operating channel, should return %NULL if | 1506 | * @set_monitor_enabled: Notify driver that there are only monitor |
1486 | * there's no single defined operating channel if for example the | 1507 | * interfaces running. |
1487 | * device implements channel hopping for multi-channel virtual interfaces. | ||
1488 | * | 1508 | * |
1489 | * @scan: Request to do a scan. If returning zero, the scan request is given | 1509 | * @scan: Request to do a scan. If returning zero, the scan request is given |
1490 | * the driver, and will be valid until passed to cfg80211_scan_done(). | 1510 | * the driver, and will be valid until passed to cfg80211_scan_done(). |
@@ -1791,15 +1811,14 @@ struct cfg80211_ops { | |||
1791 | struct net_device *dev, | 1811 | struct net_device *dev, |
1792 | u16 noack_map); | 1812 | u16 noack_map); |
1793 | 1813 | ||
1794 | struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy, | ||
1795 | enum nl80211_channel_type *type); | ||
1796 | |||
1797 | int (*get_et_sset_count)(struct wiphy *wiphy, | 1814 | int (*get_et_sset_count)(struct wiphy *wiphy, |
1798 | struct net_device *dev, int sset); | 1815 | struct net_device *dev, int sset); |
1799 | void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, | 1816 | void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, |
1800 | struct ethtool_stats *stats, u64 *data); | 1817 | struct ethtool_stats *stats, u64 *data); |
1801 | void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, | 1818 | void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, |
1802 | u32 sset, u8 *data); | 1819 | u32 sset, u8 *data); |
1820 | |||
1821 | void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled); | ||
1803 | }; | 1822 | }; |
1804 | 1823 | ||
1805 | /* | 1824 | /* |
@@ -2153,7 +2172,9 @@ struct wiphy { | |||
2153 | char fw_version[ETHTOOL_BUSINFO_LEN]; | 2172 | char fw_version[ETHTOOL_BUSINFO_LEN]; |
2154 | u32 hw_version; | 2173 | u32 hw_version; |
2155 | 2174 | ||
2175 | #ifdef CONFIG_PM | ||
2156 | struct wiphy_wowlan_support wowlan; | 2176 | struct wiphy_wowlan_support wowlan; |
2177 | #endif | ||
2157 | 2178 | ||
2158 | u16 max_remain_on_channel_duration; | 2179 | u16 max_remain_on_channel_duration; |
2159 | 2180 | ||
@@ -2389,6 +2410,11 @@ struct wireless_dev { | |||
2389 | struct ieee80211_channel *preset_chan; | 2410 | struct ieee80211_channel *preset_chan; |
2390 | enum nl80211_channel_type preset_chantype; | 2411 | enum nl80211_channel_type preset_chantype; |
2391 | 2412 | ||
2413 | /* for AP and mesh channel tracking */ | ||
2414 | struct ieee80211_channel *channel; | ||
2415 | |||
2416 | bool ibss_fixed; | ||
2417 | |||
2392 | bool ps; | 2418 | bool ps; |
2393 | int ps_timeout; | 2419 | int ps_timeout; |
2394 | 2420 | ||
@@ -3463,7 +3489,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
3463 | * | 3489 | * |
3464 | * return 0 if MCS index >= 32 | 3490 | * return 0 if MCS index >= 32 |
3465 | */ | 3491 | */ |
3466 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); | 3492 | u32 cfg80211_calculate_bitrate(struct rate_info *rate); |
3467 | 3493 | ||
3468 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 3494 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
3469 | 3495 | ||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 670a58ba8a41..e3fa90ce9ecb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -475,7 +475,7 @@ enum mac80211_rate_control_flags { | |||
475 | #define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 | 475 | #define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 |
476 | 476 | ||
477 | /* maximum number of rate stages */ | 477 | /* maximum number of rate stages */ |
478 | #define IEEE80211_TX_MAX_RATES 5 | 478 | #define IEEE80211_TX_MAX_RATES 4 |
479 | 479 | ||
480 | /** | 480 | /** |
481 | * struct ieee80211_tx_rate - rate selection/status | 481 | * struct ieee80211_tx_rate - rate selection/status |
@@ -563,11 +563,11 @@ struct ieee80211_tx_info { | |||
563 | } control; | 563 | } control; |
564 | struct { | 564 | struct { |
565 | struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; | 565 | struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; |
566 | u8 ampdu_ack_len; | ||
567 | int ack_signal; | 566 | int ack_signal; |
567 | u8 ampdu_ack_len; | ||
568 | u8 ampdu_len; | 568 | u8 ampdu_len; |
569 | u8 antenna; | 569 | u8 antenna; |
570 | /* 14 bytes free */ | 570 | /* 21 bytes free */ |
571 | } status; | 571 | } status; |
572 | struct { | 572 | struct { |
573 | struct ieee80211_tx_rate driver_rates[ | 573 | struct ieee80211_tx_rate driver_rates[ |
@@ -634,7 +634,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | |||
634 | info->status.rates[i].count = 0; | 634 | info->status.rates[i].count = 0; |
635 | 635 | ||
636 | BUILD_BUG_ON( | 636 | BUILD_BUG_ON( |
637 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); | 637 | offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); |
638 | memset(&info->status.ampdu_ack_len, 0, | 638 | memset(&info->status.ampdu_ack_len, 0, |
639 | sizeof(struct ieee80211_tx_info) - | 639 | sizeof(struct ieee80211_tx_info) - |
640 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); | 640 | offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); |
@@ -1896,19 +1896,6 @@ enum ieee80211_rate_control_changed { | |||
1896 | * The low-level driver should send the frame out based on | 1896 | * The low-level driver should send the frame out based on |
1897 | * configuration in the TX control data. This handler should, | 1897 | * configuration in the TX control data. This handler should, |
1898 | * preferably, never fail and stop queues appropriately. | 1898 | * preferably, never fail and stop queues appropriately. |
1899 | * This must be implemented if @tx_frags is not. | ||
1900 | * Must be atomic. | ||
1901 | * | ||
1902 | * @tx_frags: Called to transmit multiple fragments of a single MSDU. | ||
1903 | * This handler must consume all fragments, sending out some of | ||
1904 | * them only is useless and it can't ask for some of them to be | ||
1905 | * queued again. If the frame is not fragmented the queue has a | ||
1906 | * single SKB only. To avoid issues with the networking stack | ||
1907 | * when TX status is reported the frames should be removed from | ||
1908 | * the skb queue. | ||
1909 | * If this is used, the tx_info @vif and @sta pointers will be | ||
1910 | * invalid -- you must not use them in that case. | ||
1911 | * This must be implemented if @tx isn't. | ||
1912 | * Must be atomic. | 1899 | * Must be atomic. |
1913 | * | 1900 | * |
1914 | * @start: Called before the first netdevice attached to the hardware | 1901 | * @start: Called before the first netdevice attached to the hardware |
@@ -2257,11 +2244,21 @@ enum ieee80211_rate_control_changed { | |||
2257 | * @get_rssi: Get current signal strength in dBm, the function is optional | 2244 | * @get_rssi: Get current signal strength in dBm, the function is optional |
2258 | * and can sleep. | 2245 | * and can sleep. |
2259 | * | 2246 | * |
2247 | * @mgd_prepare_tx: Prepare for transmitting a management frame for association | ||
2248 | * before associated. In multi-channel scenarios, a virtual interface is | ||
2249 | * bound to a channel before it is associated, but as it isn't associated | ||
2250 | * yet it need not necessarily be given airtime, in particular since any | ||
2251 | * transmission to a P2P GO needs to be synchronized against the GO's | ||
2252 | * powersave state. mac80211 will call this function before transmitting a | ||
2253 | * management frame prior to having successfully associated to allow the | ||
2254 | * driver to give it channel time for the transmission, to get a response | ||
2255 | * and to be able to synchronize with the GO. | ||
2256 | * The callback will be called before each transmission and upon return | ||
2257 | * mac80211 will transmit the frame right away. | ||
2258 | * The callback is optional and can (should!) sleep. | ||
2260 | */ | 2259 | */ |
2261 | struct ieee80211_ops { | 2260 | struct ieee80211_ops { |
2262 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 2261 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
2263 | void (*tx_frags)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
2264 | struct ieee80211_sta *sta, struct sk_buff_head *skbs); | ||
2265 | int (*start)(struct ieee80211_hw *hw); | 2262 | int (*start)(struct ieee80211_hw *hw); |
2266 | void (*stop)(struct ieee80211_hw *hw); | 2263 | void (*stop)(struct ieee80211_hw *hw); |
2267 | #ifdef CONFIG_PM | 2264 | #ifdef CONFIG_PM |
@@ -2398,6 +2395,9 @@ struct ieee80211_ops { | |||
2398 | u32 sset, u8 *data); | 2395 | u32 sset, u8 *data); |
2399 | int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2396 | int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2400 | struct ieee80211_sta *sta, s8 *rssi_dbm); | 2397 | struct ieee80211_sta *sta, s8 *rssi_dbm); |
2398 | |||
2399 | void (*mgd_prepare_tx)(struct ieee80211_hw *hw, | ||
2400 | struct ieee80211_vif *vif); | ||
2401 | }; | 2401 | }; |
2402 | 2402 | ||
2403 | /** | 2403 | /** |
@@ -3832,12 +3832,6 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, | |||
3832 | 3832 | ||
3833 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); | 3833 | void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); |
3834 | 3834 | ||
3835 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | ||
3836 | struct sk_buff *skb, bool need_basic); | ||
3837 | |||
3838 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, | ||
3839 | struct sk_buff *skb, bool need_basic); | ||
3840 | |||
3841 | /** | 3835 | /** |
3842 | * ieee80211_ave_rssi - report the average rssi for the specified interface | 3836 | * ieee80211_ave_rssi - report the average rssi for the specified interface |
3843 | * | 3837 | * |
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index e30e6a869714..f5169b04f082 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h | |||
@@ -44,10 +44,20 @@ struct nfc_hci_ops { | |||
44 | struct nfc_target *target); | 44 | struct nfc_target *target); |
45 | }; | 45 | }; |
46 | 46 | ||
47 | #define NFC_HCI_MAX_CUSTOM_GATES 15 | 47 | /* Pipes */ |
48 | #define NFC_HCI_INVALID_PIPE 0x80 | ||
49 | #define NFC_HCI_LINK_MGMT_PIPE 0x00 | ||
50 | #define NFC_HCI_ADMIN_PIPE 0x01 | ||
51 | |||
52 | struct nfc_hci_gate { | ||
53 | u8 gate; | ||
54 | u8 pipe; | ||
55 | }; | ||
56 | |||
57 | #define NFC_HCI_MAX_CUSTOM_GATES 50 | ||
48 | struct nfc_hci_init_data { | 58 | struct nfc_hci_init_data { |
49 | u8 gate_count; | 59 | u8 gate_count; |
50 | u8 gates[NFC_HCI_MAX_CUSTOM_GATES]; | 60 | struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES]; |
51 | char session_id[9]; | 61 | char session_id[9]; |
52 | }; | 62 | }; |
53 | 63 | ||
@@ -112,6 +122,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev); | |||
112 | void nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata); | 122 | void nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata); |
113 | void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev); | 123 | void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev); |
114 | 124 | ||
125 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err); | ||
126 | |||
115 | /* Host IDs */ | 127 | /* Host IDs */ |
116 | #define NFC_HCI_HOST_CONTROLLER_ID 0x00 | 128 | #define NFC_HCI_HOST_CONTROLLER_ID 0x00 |
117 | #define NFC_HCI_TERMINAL_HOST_ID 0x01 | 129 | #define NFC_HCI_TERMINAL_HOST_ID 0x01 |
@@ -180,7 +192,8 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, | |||
180 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb); | 192 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb); |
181 | 193 | ||
182 | /* connecting to gates and sending hci instructions */ | 194 | /* connecting to gates and sending hci instructions */ |
183 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate); | 195 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, |
196 | u8 pipe); | ||
184 | int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate); | 197 | int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate); |
185 | int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev); | 198 | int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev); |
186 | int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, | 199 | int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, |
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 180964b954ab..6431f5e39022 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h | |||
@@ -204,4 +204,6 @@ int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode, | |||
204 | int nfc_tm_deactivated(struct nfc_dev *dev); | 204 | int nfc_tm_deactivated(struct nfc_dev *dev); |
205 | int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb); | 205 | int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb); |
206 | 206 | ||
207 | void nfc_driver_failure(struct nfc_dev *dev, int err); | ||
208 | |||
207 | #endif /* __NET_NFC_H */ | 209 | #endif /* __NET_NFC_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c2a2dcbfdf01..ccbe2413142a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2668,8 +2668,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2668 | tf->u.setup_req.capability = | 2668 | tf->u.setup_req.capability = |
2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2669 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2670 | 2670 | ||
2671 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2671 | ieee80211_add_srates_ie(sdata, skb, false); |
2672 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2672 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2673 | ieee80211_tdls_add_ext_capab(skb); | 2673 | ieee80211_tdls_add_ext_capab(skb); |
2674 | break; | 2674 | break; |
2675 | case WLAN_TDLS_SETUP_RESPONSE: | 2675 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -2682,8 +2682,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2682 | tf->u.setup_resp.capability = | 2682 | tf->u.setup_resp.capability = |
2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2683 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2684 | 2684 | ||
2685 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2685 | ieee80211_add_srates_ie(sdata, skb, false); |
2686 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2686 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2687 | ieee80211_tdls_add_ext_capab(skb); | 2687 | ieee80211_tdls_add_ext_capab(skb); |
2688 | break; | 2688 | break; |
2689 | case WLAN_TDLS_SETUP_CONFIRM: | 2689 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -2743,8 +2743,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
2743 | mgmt->u.action.u.tdls_discover_resp.capability = | 2743 | mgmt->u.action.u.tdls_discover_resp.capability = |
2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2744 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2745 | 2745 | ||
2746 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2746 | ieee80211_add_srates_ie(sdata, skb, false); |
2747 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2747 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2748 | ieee80211_tdls_add_ext_capab(skb); | 2748 | ieee80211_tdls_add_ext_capab(skb); |
2749 | break; | 2749 | break; |
2750 | default: | 2750 | default: |
@@ -2980,14 +2980,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
2980 | return 0; | 2980 | return 0; |
2981 | } | 2981 | } |
2982 | 2982 | ||
2983 | static struct ieee80211_channel * | 2983 | static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled) |
2984 | ieee80211_wiphy_get_channel(struct wiphy *wiphy, | ||
2985 | enum nl80211_channel_type *type) | ||
2986 | { | 2984 | { |
2987 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2985 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2988 | 2986 | ||
2989 | *type = local->_oper_channel_type; | 2987 | if (enabled) |
2990 | return local->oper_channel; | 2988 | WARN_ON(ieee80211_add_virtual_monitor(local)); |
2989 | else | ||
2990 | ieee80211_del_virtual_monitor(local); | ||
2991 | } | 2991 | } |
2992 | 2992 | ||
2993 | #ifdef CONFIG_PM | 2993 | #ifdef CONFIG_PM |
@@ -3063,8 +3063,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3063 | .tdls_oper = ieee80211_tdls_oper, | 3063 | .tdls_oper = ieee80211_tdls_oper, |
3064 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3064 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3065 | .probe_client = ieee80211_probe_client, | 3065 | .probe_client = ieee80211_probe_client, |
3066 | .get_channel = ieee80211_wiphy_get_channel, | ||
3067 | .set_noack_map = ieee80211_set_noack_map, | 3066 | .set_noack_map = ieee80211_set_noack_map, |
3067 | .set_monitor_enabled = ieee80211_set_monitor_enabled, | ||
3068 | #ifdef CONFIG_PM | 3068 | #ifdef CONFIG_PM |
3069 | .set_wakeup = ieee80211_set_wakeup, | 3069 | .set_wakeup = ieee80211_set_wakeup, |
3070 | #endif | 3070 | #endif |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb482..090d08ff22c4 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
283 | 283 | ||
284 | lockdep_assert_held(&sdata->local->key_mtx); | 284 | lockdep_assert_held(&sdata->local->key_mtx); |
285 | 285 | ||
286 | if (sdata->debugfs.default_unicast_key) { | ||
287 | debugfs_remove(sdata->debugfs.default_unicast_key); | ||
288 | sdata->debugfs.default_unicast_key = NULL; | ||
289 | } | ||
290 | |||
286 | if (sdata->default_unicast_key) { | 291 | if (sdata->default_unicast_key) { |
287 | key = key_mtx_dereference(sdata->local, | 292 | key = key_mtx_dereference(sdata->local, |
288 | sdata->default_unicast_key); | 293 | sdata->default_unicast_key); |
@@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
290 | sdata->debugfs.default_unicast_key = | 295 | sdata->debugfs.default_unicast_key = |
291 | debugfs_create_symlink("default_unicast_key", | 296 | debugfs_create_symlink("default_unicast_key", |
292 | sdata->debugfs.dir, buf); | 297 | sdata->debugfs.dir, buf); |
293 | } else { | 298 | } |
294 | debugfs_remove(sdata->debugfs.default_unicast_key); | 299 | |
295 | sdata->debugfs.default_unicast_key = NULL; | 300 | if (sdata->debugfs.default_multicast_key) { |
301 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
302 | sdata->debugfs.default_multicast_key = NULL; | ||
296 | } | 303 | } |
297 | 304 | ||
298 | if (sdata->default_multicast_key) { | 305 | if (sdata->default_multicast_key) { |
@@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
302 | sdata->debugfs.default_multicast_key = | 309 | sdata->debugfs.default_multicast_key = |
303 | debugfs_create_symlink("default_multicast_key", | 310 | debugfs_create_symlink("default_multicast_key", |
304 | sdata->debugfs.dir, buf); | 311 | sdata->debugfs.dir, buf); |
305 | } else { | ||
306 | debugfs_remove(sdata->debugfs.default_multicast_key); | ||
307 | sdata->debugfs.default_multicast_key = NULL; | ||
308 | } | 312 | } |
309 | } | 313 | } |
310 | 314 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 44e8c1242781..df9203199102 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | |||
27 | local->ops->tx(&local->hw, skb); | 27 | local->ops->tx(&local->hw, skb); |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline void drv_tx_frags(struct ieee80211_local *local, | ||
31 | struct ieee80211_vif *vif, | ||
32 | struct ieee80211_sta *sta, | ||
33 | struct sk_buff_head *skbs) | ||
34 | { | ||
35 | local->ops->tx_frags(&local->hw, vif, sta, skbs); | ||
36 | } | ||
37 | |||
38 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, | 30 | static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, |
39 | u32 sset, u8 *data) | 31 | u32 sset, u8 *data) |
40 | { | 32 | { |
@@ -860,4 +852,18 @@ static inline int drv_get_rssi(struct ieee80211_local *local, | |||
860 | 852 | ||
861 | return ret; | 853 | return ret; |
862 | } | 854 | } |
855 | |||
856 | static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, | ||
857 | struct ieee80211_sub_if_data *sdata) | ||
858 | { | ||
859 | might_sleep(); | ||
860 | |||
861 | check_sdata_in_driver(sdata); | ||
862 | WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); | ||
863 | |||
864 | trace_drv_mgd_prepare_tx(local, sdata); | ||
865 | if (local->ops->mgd_prepare_tx) | ||
866 | local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); | ||
867 | trace_drv_return_void(local); | ||
868 | } | ||
863 | #endif /* __MAC80211_DRIVER_OPS */ | 869 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f834a005e1c5..e0423f8c0ce1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1284,7 +1284,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
1284 | enum nl80211_iftype type); | 1284 | enum nl80211_iftype type); |
1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); | 1285 | void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); |
1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); | 1286 | void ieee80211_remove_interfaces(struct ieee80211_local *local); |
1287 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | ||
1288 | void ieee80211_recalc_idle(struct ieee80211_local *local); | 1287 | void ieee80211_recalc_idle(struct ieee80211_local *local); |
1289 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | 1288 | void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, |
1290 | const int offset); | 1289 | const int offset); |
@@ -1481,6 +1480,16 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1481 | struct ieee80211_channel *channel, | 1480 | struct ieee80211_channel *channel, |
1482 | enum nl80211_channel_type channel_type, | 1481 | enum nl80211_channel_type channel_type, |
1483 | u16 prot_mode); | 1482 | u16 prot_mode); |
1483 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1484 | u32 cap); | ||
1485 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1486 | struct sk_buff *skb, bool need_basic); | ||
1487 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, | ||
1488 | struct sk_buff *skb, bool need_basic); | ||
1489 | |||
1490 | /* virtual monitor */ | ||
1491 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local); | ||
1492 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local); | ||
1484 | 1493 | ||
1485 | /* channel management */ | 1494 | /* channel management */ |
1486 | enum ieee80211_chan_mode { | 1495 | enum ieee80211_chan_mode { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 58c2ab3d483a..fbef7a1ada7a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -43,6 +43,127 @@ | |||
43 | */ | 43 | */ |
44 | 44 | ||
45 | 45 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
47 | const char *reason) | ||
48 | { | ||
49 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
50 | return 0; | ||
51 | |||
52 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
53 | return IEEE80211_CONF_CHANGE_IDLE; | ||
54 | } | ||
55 | |||
56 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
57 | { | ||
58 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
59 | return 0; | ||
60 | |||
61 | drv_flush(local, false); | ||
62 | |||
63 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
64 | return IEEE80211_CONF_CHANGE_IDLE; | ||
65 | } | ||
66 | |||
67 | static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
68 | { | ||
69 | struct ieee80211_sub_if_data *sdata; | ||
70 | int count = 0; | ||
71 | bool working = false, scanning = false; | ||
72 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
73 | struct ieee80211_roc_work *roc; | ||
74 | |||
75 | #ifdef CONFIG_PROVE_LOCKING | ||
76 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
77 | !lockdep_is_held(&local->iflist_mtx)); | ||
78 | #endif | ||
79 | lockdep_assert_held(&local->mtx); | ||
80 | |||
81 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
82 | if (!ieee80211_sdata_running(sdata)) { | ||
83 | sdata->vif.bss_conf.idle = true; | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
88 | |||
89 | /* do not count disabled managed interfaces */ | ||
90 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
91 | !sdata->u.mgd.associated && | ||
92 | !sdata->u.mgd.auth_data && | ||
93 | !sdata->u.mgd.assoc_data) { | ||
94 | sdata->vif.bss_conf.idle = true; | ||
95 | continue; | ||
96 | } | ||
97 | /* do not count unused IBSS interfaces */ | ||
98 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
99 | !sdata->u.ibss.ssid_len) { | ||
100 | sdata->vif.bss_conf.idle = true; | ||
101 | continue; | ||
102 | } | ||
103 | /* count everything else */ | ||
104 | sdata->vif.bss_conf.idle = false; | ||
105 | count++; | ||
106 | } | ||
107 | |||
108 | if (!local->ops->remain_on_channel) { | ||
109 | list_for_each_entry(roc, &local->roc_list, list) { | ||
110 | working = true; | ||
111 | roc->sdata->vif.bss_conf.idle = false; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | if (local->scan_sdata && | ||
116 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
117 | scanning = true; | ||
118 | local->scan_sdata->vif.bss_conf.idle = false; | ||
119 | } | ||
120 | |||
121 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
122 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
123 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
124 | continue; | ||
125 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
126 | continue; | ||
127 | if (!ieee80211_sdata_running(sdata)) | ||
128 | continue; | ||
129 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
130 | } | ||
131 | |||
132 | if (working || scanning) | ||
133 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
134 | else | ||
135 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
136 | |||
137 | if (count) | ||
138 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
139 | else | ||
140 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
141 | |||
142 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
143 | |||
144 | if (working) | ||
145 | return ieee80211_idle_off(local, "working"); | ||
146 | if (scanning) | ||
147 | return ieee80211_idle_off(local, "scanning"); | ||
148 | if (!count) | ||
149 | return ieee80211_idle_on(local); | ||
150 | else | ||
151 | return ieee80211_idle_off(local, "in use"); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
157 | { | ||
158 | u32 chg; | ||
159 | |||
160 | mutex_lock(&local->iflist_mtx); | ||
161 | chg = __ieee80211_recalc_idle(local); | ||
162 | mutex_unlock(&local->iflist_mtx); | ||
163 | if (chg) | ||
164 | ieee80211_hw_config(local, chg); | ||
165 | } | ||
166 | |||
46 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | 167 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) |
47 | { | 168 | { |
48 | int meshhdrlen; | 169 | int meshhdrlen; |
@@ -209,7 +330,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) | |||
209 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 330 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
210 | } | 331 | } |
211 | 332 | ||
212 | static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | 333 | int ieee80211_add_virtual_monitor(struct ieee80211_local *local) |
213 | { | 334 | { |
214 | struct ieee80211_sub_if_data *sdata; | 335 | struct ieee80211_sub_if_data *sdata; |
215 | int ret; | 336 | int ret; |
@@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
250 | return 0; | 371 | return 0; |
251 | } | 372 | } |
252 | 373 | ||
253 | static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) | 374 | void ieee80211_del_virtual_monitor(struct ieee80211_local *local) |
254 | { | 375 | { |
255 | struct ieee80211_sub_if_data *sdata; | 376 | struct ieee80211_sub_if_data *sdata; |
256 | 377 | ||
@@ -366,12 +487,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
366 | break; | 487 | break; |
367 | } | 488 | } |
368 | 489 | ||
369 | if (local->monitors == 0 && local->open_count == 0) { | ||
370 | res = ieee80211_add_virtual_monitor(local); | ||
371 | if (res) | ||
372 | goto err_stop; | ||
373 | } | ||
374 | |||
375 | /* must be before the call to ieee80211_configure_filter */ | 490 | /* must be before the call to ieee80211_configure_filter */ |
376 | local->monitors++; | 491 | local->monitors++; |
377 | if (local->monitors == 1) { | 492 | if (local->monitors == 1) { |
@@ -386,8 +501,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
386 | break; | 501 | break; |
387 | default: | 502 | default: |
388 | if (coming_up) { | 503 | if (coming_up) { |
389 | ieee80211_del_virtual_monitor(local); | ||
390 | |||
391 | res = drv_add_interface(local, sdata); | 504 | res = drv_add_interface(local, sdata); |
392 | if (res) | 505 | if (res) |
393 | goto err_stop; | 506 | goto err_stop; |
@@ -622,7 +735,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
622 | if (local->monitors == 0) { | 735 | if (local->monitors == 0) { |
623 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; | 736 | local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; |
624 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; | 737 | hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; |
625 | ieee80211_del_virtual_monitor(local); | ||
626 | } | 738 | } |
627 | 739 | ||
628 | ieee80211_adjust_monitor_flags(sdata, -1); | 740 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -696,9 +808,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
696 | } | 808 | } |
697 | } | 809 | } |
698 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 810 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
699 | |||
700 | if (local->monitors == local->open_count && local->monitors > 0) | ||
701 | ieee80211_add_virtual_monitor(local); | ||
702 | } | 811 | } |
703 | 812 | ||
704 | static int ieee80211_stop(struct net_device *dev) | 813 | static int ieee80211_stop(struct net_device *dev) |
@@ -1403,127 +1512,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1403 | list_del(&unreg_list); | 1512 | list_del(&unreg_list); |
1404 | } | 1513 | } |
1405 | 1514 | ||
1406 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | ||
1407 | const char *reason) | ||
1408 | { | ||
1409 | if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) | ||
1410 | return 0; | ||
1411 | |||
1412 | local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; | ||
1413 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1414 | } | ||
1415 | |||
1416 | static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||
1417 | { | ||
1418 | if (local->hw.conf.flags & IEEE80211_CONF_IDLE) | ||
1419 | return 0; | ||
1420 | |||
1421 | drv_flush(local, false); | ||
1422 | |||
1423 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||
1424 | return IEEE80211_CONF_CHANGE_IDLE; | ||
1425 | } | ||
1426 | |||
1427 | u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1428 | { | ||
1429 | struct ieee80211_sub_if_data *sdata; | ||
1430 | int count = 0; | ||
1431 | bool working = false, scanning = false; | ||
1432 | unsigned int led_trig_start = 0, led_trig_stop = 0; | ||
1433 | struct ieee80211_roc_work *roc; | ||
1434 | |||
1435 | #ifdef CONFIG_PROVE_LOCKING | ||
1436 | WARN_ON(debug_locks && !lockdep_rtnl_is_held() && | ||
1437 | !lockdep_is_held(&local->iflist_mtx)); | ||
1438 | #endif | ||
1439 | lockdep_assert_held(&local->mtx); | ||
1440 | |||
1441 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1442 | if (!ieee80211_sdata_running(sdata)) { | ||
1443 | sdata->vif.bss_conf.idle = true; | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | sdata->old_idle = sdata->vif.bss_conf.idle; | ||
1448 | |||
1449 | /* do not count disabled managed interfaces */ | ||
1450 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
1451 | !sdata->u.mgd.associated && | ||
1452 | !sdata->u.mgd.auth_data && | ||
1453 | !sdata->u.mgd.assoc_data) { | ||
1454 | sdata->vif.bss_conf.idle = true; | ||
1455 | continue; | ||
1456 | } | ||
1457 | /* do not count unused IBSS interfaces */ | ||
1458 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||
1459 | !sdata->u.ibss.ssid_len) { | ||
1460 | sdata->vif.bss_conf.idle = true; | ||
1461 | continue; | ||
1462 | } | ||
1463 | /* count everything else */ | ||
1464 | sdata->vif.bss_conf.idle = false; | ||
1465 | count++; | ||
1466 | } | ||
1467 | |||
1468 | if (!local->ops->remain_on_channel) { | ||
1469 | list_for_each_entry(roc, &local->roc_list, list) { | ||
1470 | working = true; | ||
1471 | roc->sdata->vif.bss_conf.idle = false; | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | if (local->scan_sdata && | ||
1476 | !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { | ||
1477 | scanning = true; | ||
1478 | local->scan_sdata->vif.bss_conf.idle = false; | ||
1479 | } | ||
1480 | |||
1481 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1482 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1483 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1484 | continue; | ||
1485 | if (sdata->old_idle == sdata->vif.bss_conf.idle) | ||
1486 | continue; | ||
1487 | if (!ieee80211_sdata_running(sdata)) | ||
1488 | continue; | ||
1489 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | ||
1490 | } | ||
1491 | |||
1492 | if (working || scanning) | ||
1493 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1494 | else | ||
1495 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | ||
1496 | |||
1497 | if (count) | ||
1498 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1499 | else | ||
1500 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; | ||
1501 | |||
1502 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | ||
1503 | |||
1504 | if (working) | ||
1505 | return ieee80211_idle_off(local, "working"); | ||
1506 | if (scanning) | ||
1507 | return ieee80211_idle_off(local, "scanning"); | ||
1508 | if (!count) | ||
1509 | return ieee80211_idle_on(local); | ||
1510 | else | ||
1511 | return ieee80211_idle_off(local, "in use"); | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | void ieee80211_recalc_idle(struct ieee80211_local *local) | ||
1517 | { | ||
1518 | u32 chg; | ||
1519 | |||
1520 | mutex_lock(&local->iflist_mtx); | ||
1521 | chg = __ieee80211_recalc_idle(local); | ||
1522 | mutex_unlock(&local->iflist_mtx); | ||
1523 | if (chg) | ||
1524 | ieee80211_hw_config(local, chg); | ||
1525 | } | ||
1526 | |||
1527 | static int netdev_notify(struct notifier_block *nb, | 1515 | static int netdev_notify(struct notifier_block *nb, |
1528 | unsigned long state, | 1516 | unsigned long state, |
1529 | void *ndev) | 1517 | void *ndev) |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0b040fb73673..c794101f8987 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -587,7 +587,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
587 | 587 | ||
588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | 588 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); |
589 | 589 | ||
590 | BUG_ON(!ops->tx && !ops->tx_frags); | 590 | BUG_ON(!ops->tx); |
591 | BUG_ON(!ops->start); | 591 | BUG_ON(!ops->start); |
592 | BUG_ON(!ops->stop); | 592 | BUG_ON(!ops->stop); |
593 | BUG_ON(!ops->config); | 593 | BUG_ON(!ops->config); |
@@ -688,7 +688,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
688 | int result, i; | 688 | int result, i; |
689 | enum ieee80211_band band; | 689 | enum ieee80211_band band; |
690 | int channels, max_bitrates; | 690 | int channels, max_bitrates; |
691 | bool supp_ht; | 691 | bool supp_ht, supp_vht; |
692 | netdev_features_t feature_whitelist; | 692 | netdev_features_t feature_whitelist; |
693 | static const u32 cipher_suites[] = { | 693 | static const u32 cipher_suites[] = { |
694 | /* keep WEP first, it may be removed below */ | 694 | /* keep WEP first, it may be removed below */ |
@@ -706,12 +706,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 706 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
707 | return -EINVAL; | 707 | return -EINVAL; |
708 | 708 | ||
709 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) | ||
710 | #ifdef CONFIG_PM | 709 | #ifdef CONFIG_PM |
711 | && (!local->ops->suspend || !local->ops->resume) | 710 | if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && |
712 | #endif | 711 | (!local->ops->suspend || !local->ops->resume)) |
713 | ) | ||
714 | return -EINVAL; | 712 | return -EINVAL; |
713 | #endif | ||
715 | 714 | ||
716 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) | 715 | if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) |
717 | return -EINVAL; | 716 | return -EINVAL; |
@@ -733,6 +732,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
733 | channels = 0; | 732 | channels = 0; |
734 | max_bitrates = 0; | 733 | max_bitrates = 0; |
735 | supp_ht = false; | 734 | supp_ht = false; |
735 | supp_vht = false; | ||
736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 736 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
737 | struct ieee80211_supported_band *sband; | 737 | struct ieee80211_supported_band *sband; |
738 | 738 | ||
@@ -750,6 +750,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
750 | if (max_bitrates < sband->n_bitrates) | 750 | if (max_bitrates < sband->n_bitrates) |
751 | max_bitrates = sband->n_bitrates; | 751 | max_bitrates = sband->n_bitrates; |
752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 752 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
753 | supp_vht = supp_vht || sband->vht_cap.vht_supported; | ||
753 | } | 754 | } |
754 | 755 | ||
755 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + | 756 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
@@ -825,6 +826,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
825 | if (supp_ht) | 826 | if (supp_ht) |
826 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); | 827 | local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); |
827 | 828 | ||
829 | if (supp_vht) | ||
830 | local->scan_ies_len += | ||
831 | 2 + sizeof(struct ieee80211_vht_capabilities); | ||
832 | |||
828 | if (!local->ops->hw_scan) { | 833 | if (!local->ops->hw_scan) { |
829 | /* For hw_scan, driver needs to set these up. */ | 834 | /* For hw_scan, driver needs to set these up. */ |
830 | local->hw.wiphy->max_scan_ssids = 4; | 835 | local->hw.wiphy->max_scan_ssids = 4; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 9ad74dd87a7b..af671b984df3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -258,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
258 | pos = skb_put(skb, 2); | 258 | pos = skb_put(skb, 2); |
259 | memcpy(pos + 2, &plid, 2); | 259 | memcpy(pos + 2, &plid, 2); |
260 | } | 260 | } |
261 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 261 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
262 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 262 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
263 | mesh_add_rsn_ie(skb, sdata) || | 263 | mesh_add_rsn_ie(skb, sdata) || |
264 | mesh_add_meshid_ie(skb, sdata) || | 264 | mesh_add_meshid_ie(skb, sdata) || |
265 | mesh_add_meshconf_ie(skb, sdata)) | 265 | mesh_add_meshconf_ie(skb, sdata)) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa69a331f374..f49f14f8ba82 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -541,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 541 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
542 | } | 542 | } |
543 | 543 | ||
544 | drv_mgd_prepare_tx(local, sdata); | ||
545 | |||
544 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 546 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
545 | ieee80211_tx_skb(sdata, skb); | 547 | ieee80211_tx_skb(sdata, skb); |
546 | } | 548 | } |
@@ -580,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
580 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) | 582 | if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) |
581 | IEEE80211_SKB_CB(skb)->flags |= | 583 | IEEE80211_SKB_CB(skb)->flags |= |
582 | IEEE80211_TX_INTFL_DONT_ENCRYPT; | 584 | IEEE80211_TX_INTFL_DONT_ENCRYPT; |
585 | |||
586 | drv_mgd_prepare_tx(local, sdata); | ||
587 | |||
583 | ieee80211_tx_skb(sdata, skb); | 588 | ieee80211_tx_skb(sdata, skb); |
584 | } | 589 | } |
585 | } | 590 | } |
@@ -902,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
902 | if (!mgd->associated) | 907 | if (!mgd->associated) |
903 | return false; | 908 | return false; |
904 | 909 | ||
905 | if (!mgd->associated->beacon_ies) | ||
906 | return false; | ||
907 | |||
908 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | 910 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | |
909 | IEEE80211_STA_CONNECTION_POLL)) | 911 | IEEE80211_STA_CONNECTION_POLL)) |
910 | return false; | 912 | return false; |
@@ -1362,6 +1364,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1362 | } | 1364 | } |
1363 | mutex_unlock(&local->sta_mtx); | 1365 | mutex_unlock(&local->sta_mtx); |
1364 | 1366 | ||
1367 | /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ | ||
1368 | if (tx) | ||
1369 | drv_flush(local, false); | ||
1370 | |||
1365 | /* deauthenticate/disassociate now */ | 1371 | /* deauthenticate/disassociate now */ |
1366 | if (tx || frame_buf) | 1372 | if (tx || frame_buf) |
1367 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, | 1373 | ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, |
@@ -1610,6 +1616,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1610 | { | 1616 | { |
1611 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1617 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
1612 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1618 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1619 | struct cfg80211_bss *cbss; | ||
1613 | struct sk_buff *skb; | 1620 | struct sk_buff *skb; |
1614 | const u8 *ssid; | 1621 | const u8 *ssid; |
1615 | int ssid_len; | 1622 | int ssid_len; |
@@ -1619,16 +1626,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1619 | 1626 | ||
1620 | ASSERT_MGD_MTX(ifmgd); | 1627 | ASSERT_MGD_MTX(ifmgd); |
1621 | 1628 | ||
1622 | if (!ifmgd->associated) | 1629 | if (ifmgd->associated) |
1630 | cbss = ifmgd->associated; | ||
1631 | else if (ifmgd->auth_data) | ||
1632 | cbss = ifmgd->auth_data->bss; | ||
1633 | else if (ifmgd->assoc_data) | ||
1634 | cbss = ifmgd->assoc_data->bss; | ||
1635 | else | ||
1623 | return NULL; | 1636 | return NULL; |
1624 | 1637 | ||
1625 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1638 | ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); |
1626 | if (WARN_ON_ONCE(ssid == NULL)) | 1639 | if (WARN_ON_ONCE(ssid == NULL)) |
1627 | ssid_len = 0; | 1640 | ssid_len = 0; |
1628 | else | 1641 | else |
1629 | ssid_len = ssid[1]; | 1642 | ssid_len = ssid[1]; |
1630 | 1643 | ||
1631 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | 1644 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, |
1632 | (u32) -1, ssid + 2, ssid_len, | 1645 | (u32) -1, ssid + 2, ssid_len, |
1633 | NULL, 0, true); | 1646 | NULL, 0, true); |
1634 | 1647 | ||
@@ -1747,6 +1760,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1747 | if (!elems.challenge) | 1760 | if (!elems.challenge) |
1748 | return; | 1761 | return; |
1749 | auth_data->expected_transaction = 4; | 1762 | auth_data->expected_transaction = 4; |
1763 | drv_mgd_prepare_tx(sdata->local, sdata); | ||
1750 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | 1764 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, |
1751 | elems.challenge - 2, elems.challenge_len + 2, | 1765 | elems.challenge - 2, elems.challenge_len + 2, |
1752 | auth_data->bss->bssid, auth_data->bss->bssid, | 1766 | auth_data->bss->bssid, auth_data->bss->bssid, |
@@ -2630,6 +2644,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
2630 | return -ETIMEDOUT; | 2644 | return -ETIMEDOUT; |
2631 | } | 2645 | } |
2632 | 2646 | ||
2647 | drv_mgd_prepare_tx(local, sdata); | ||
2648 | |||
2633 | if (auth_data->bss->proberesp_ies) { | 2649 | if (auth_data->bss->proberesp_ies) { |
2634 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", | 2650 | sdata_info(sdata, "send auth to %pM (try %d/%d)\n", |
2635 | auth_data->bss->bssid, auth_data->tries, | 2651 | auth_data->bss->bssid, auth_data->tries, |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 2e60f4acd027..e1e9d10ec2e7 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -1244,6 +1244,13 @@ TRACE_EVENT(drv_get_rssi, | |||
1244 | ) | 1244 | ) |
1245 | ); | 1245 | ); |
1246 | 1246 | ||
1247 | DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, | ||
1248 | TP_PROTO(struct ieee80211_local *local, | ||
1249 | struct ieee80211_sub_if_data *sdata), | ||
1250 | |||
1251 | TP_ARGS(local, sdata) | ||
1252 | ); | ||
1253 | |||
1247 | /* | 1254 | /* |
1248 | * Tracing for API calls that drivers call. | 1255 | * Tracing for API calls that drivers call. |
1249 | */ | 1256 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ec8f53467374..c9d2175d15c1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, | |||
140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) | 140 | if (r->flags & IEEE80211_RATE_MANDATORY_A) |
141 | mrate = r->bitrate; | 141 | mrate = r->bitrate; |
142 | break; | 142 | break; |
143 | case IEEE80211_BAND_60GHZ: | ||
144 | /* TODO, for now fall through */ | ||
143 | case IEEE80211_NUM_BANDS: | 145 | case IEEE80211_NUM_BANDS: |
144 | WARN_ON(1); | 146 | WARN_ON(1); |
145 | break; | 147 | break; |
@@ -957,8 +959,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
957 | info->control.rates[1].idx = -1; | 959 | info->control.rates[1].idx = -1; |
958 | info->control.rates[2].idx = -1; | 960 | info->control.rates[2].idx = -1; |
959 | info->control.rates[3].idx = -1; | 961 | info->control.rates[3].idx = -1; |
960 | info->control.rates[4].idx = -1; | 962 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4); |
961 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | ||
962 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 963 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
963 | } else { | 964 | } else { |
964 | hdr->frame_control &= ~morefrags; | 965 | hdr->frame_control &= ~morefrags; |
@@ -1293,11 +1294,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1293 | break; | 1294 | break; |
1294 | } | 1295 | } |
1295 | 1296 | ||
1296 | if (local->ops->tx_frags) | 1297 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, |
1297 | drv_tx_frags(local, vif, pubsta, skbs); | 1298 | txpending); |
1298 | else | ||
1299 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, | ||
1300 | txpending); | ||
1301 | 1299 | ||
1302 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | 1300 | ieee80211_tpt_led_trig_tx(local, fc, led_len); |
1303 | ieee80211_led_tx(local, 1); | 1301 | ieee80211_led_tx(local, 1); |
@@ -2420,9 +2418,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2420 | *pos++ = WLAN_EID_SSID; | 2418 | *pos++ = WLAN_EID_SSID; |
2421 | *pos++ = 0x0; | 2419 | *pos++ = 0x0; |
2422 | 2420 | ||
2423 | if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || | 2421 | if (ieee80211_add_srates_ie(sdata, skb, true) || |
2424 | mesh_add_ds_params_ie(skb, sdata) || | 2422 | mesh_add_ds_params_ie(skb, sdata) || |
2425 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || | 2423 | ieee80211_add_ext_srates_ie(sdata, skb, true) || |
2426 | mesh_add_rsn_ie(skb, sdata) || | 2424 | mesh_add_rsn_ie(skb, sdata) || |
2427 | mesh_add_ht_cap_ie(skb, sdata) || | 2425 | mesh_add_ht_cap_ie(skb, sdata) || |
2428 | mesh_add_ht_oper_ie(skb, sdata) || | 2426 | mesh_add_ht_oper_ie(skb, sdata) || |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 242ecde381f6..64493a7bef1a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); | |||
268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | 268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) |
269 | { | 269 | { |
270 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
271 | int n_acs = IEEE80211_NUM_ACS; | ||
272 | |||
273 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
274 | n_acs = 1; | ||
271 | 275 | ||
272 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 276 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
273 | int ac; | 277 | int ac; |
@@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
279 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) | 283 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) |
280 | continue; | 284 | continue; |
281 | 285 | ||
282 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 286 | for (ac = 0; ac < n_acs; ac++) { |
283 | int ac_queue = sdata->vif.hw_queue[ac]; | 287 | int ac_queue = sdata->vif.hw_queue[ac]; |
284 | 288 | ||
285 | if (ac_queue == queue || | 289 | if (ac_queue == queue || |
@@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
341 | { | 345 | { |
342 | struct ieee80211_local *local = hw_to_local(hw); | 346 | struct ieee80211_local *local = hw_to_local(hw); |
343 | struct ieee80211_sub_if_data *sdata; | 347 | struct ieee80211_sub_if_data *sdata; |
348 | int n_acs = IEEE80211_NUM_ACS; | ||
344 | 349 | ||
345 | trace_stop_queue(local, queue, reason); | 350 | trace_stop_queue(local, queue, reason); |
346 | 351 | ||
@@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
352 | 357 | ||
353 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 358 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
354 | 359 | ||
360 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
361 | n_acs = 1; | ||
362 | |||
355 | rcu_read_lock(); | 363 | rcu_read_lock(); |
356 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 364 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
357 | int ac; | 365 | int ac; |
358 | 366 | ||
359 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 367 | for (ac = 0; ac < n_acs; ac++) { |
360 | if (sdata->vif.hw_queue[ac] == queue || | 368 | if (sdata->vif.hw_queue[ac] == queue || |
361 | sdata->vif.cab_queue == queue) | 369 | sdata->vif.cab_queue == queue) |
362 | netif_stop_subqueue(sdata->dev, ac); | 370 | netif_stop_subqueue(sdata->dev, ac); |
@@ -1072,6 +1080,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1072 | pos += noffset - offset; | 1080 | pos += noffset - offset; |
1073 | } | 1081 | } |
1074 | 1082 | ||
1083 | if (sband->vht_cap.vht_supported) | ||
1084 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | ||
1085 | sband->vht_cap.cap); | ||
1086 | |||
1075 | return pos - buffer; | 1087 | return pos - buffer; |
1076 | } | 1088 | } |
1077 | 1089 | ||
@@ -1411,10 +1423,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1411 | if (ieee80211_sdata_running(sdata)) | 1423 | if (ieee80211_sdata_running(sdata)) |
1412 | ieee80211_enable_keys(sdata); | 1424 | ieee80211_enable_keys(sdata); |
1413 | 1425 | ||
1426 | wake_up: | ||
1414 | local->in_reconfig = false; | 1427 | local->in_reconfig = false; |
1415 | barrier(); | 1428 | barrier(); |
1416 | 1429 | ||
1417 | wake_up: | ||
1418 | /* | 1430 | /* |
1419 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation | 1431 | * Clear the WLAN_STA_BLOCK_BA flag so new aggregation |
1420 | * sessions can be established after a resume. | 1432 | * sessions can be established after a resume. |
@@ -1699,6 +1711,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | |||
1699 | return pos; | 1711 | return pos; |
1700 | } | 1712 | } |
1701 | 1713 | ||
1714 | u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | ||
1715 | u32 cap) | ||
1716 | { | ||
1717 | __le32 tmp; | ||
1718 | |||
1719 | *pos++ = WLAN_EID_VHT_CAPABILITY; | ||
1720 | *pos++ = sizeof(struct ieee80211_vht_capabilities); | ||
1721 | memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); | ||
1722 | |||
1723 | /* capability flags */ | ||
1724 | tmp = cpu_to_le32(cap); | ||
1725 | memcpy(pos, &tmp, sizeof(u32)); | ||
1726 | pos += sizeof(u32); | ||
1727 | |||
1728 | /* VHT MCS set */ | ||
1729 | memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); | ||
1730 | pos += sizeof(vht_cap->vht_mcs); | ||
1731 | |||
1732 | return pos; | ||
1733 | } | ||
1734 | |||
1702 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1735 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1703 | struct ieee80211_channel *channel, | 1736 | struct ieee80211_channel *channel, |
1704 | enum nl80211_channel_type channel_type, | 1737 | enum nl80211_channel_type channel_type, |
@@ -1764,15 +1797,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) | |||
1764 | return channel_type; | 1797 | return channel_type; |
1765 | } | 1798 | } |
1766 | 1799 | ||
1767 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | 1800 | int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, |
1768 | struct sk_buff *skb, bool need_basic) | 1801 | struct sk_buff *skb, bool need_basic) |
1769 | { | 1802 | { |
1770 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1771 | struct ieee80211_local *local = sdata->local; | 1803 | struct ieee80211_local *local = sdata->local; |
1772 | struct ieee80211_supported_band *sband; | 1804 | struct ieee80211_supported_band *sband; |
1773 | int rate; | 1805 | int rate; |
1774 | u8 i, rates, *pos; | 1806 | u8 i, rates, *pos; |
1775 | u32 basic_rates = vif->bss_conf.basic_rates; | 1807 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1776 | 1808 | ||
1777 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1778 | rates = sband->n_bitrates; | 1810 | rates = sband->n_bitrates; |
@@ -1796,15 +1828,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, | |||
1796 | return 0; | 1828 | return 0; |
1797 | } | 1829 | } |
1798 | 1830 | ||
1799 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, | 1831 | int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, |
1800 | struct sk_buff *skb, bool need_basic) | 1832 | struct sk_buff *skb, bool need_basic) |
1801 | { | 1833 | { |
1802 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1803 | struct ieee80211_local *local = sdata->local; | 1834 | struct ieee80211_local *local = sdata->local; |
1804 | struct ieee80211_supported_band *sband; | 1835 | struct ieee80211_supported_band *sband; |
1805 | int rate; | 1836 | int rate; |
1806 | u8 i, exrates, *pos; | 1837 | u8 i, exrates, *pos; |
1807 | u32 basic_rates = vif->bss_conf.basic_rates; | 1838 | u32 basic_rates = sdata->vif.bss_conf.basic_rates; |
1808 | 1839 | ||
1809 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1840 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1810 | exrates = sband->n_bitrates; | 1841 | exrates = sband->n_bitrates; |
diff --git a/net/nfc/core.c b/net/nfc/core.c index 4177bb5104b9..ff749794bc5b 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/nfc.h> | 30 | #include <linux/nfc.h> |
31 | 31 | ||
32 | #include <net/genetlink.h> | ||
33 | |||
32 | #include "nfc.h" | 34 | #include "nfc.h" |
33 | 35 | ||
34 | #define VERSION "0.1" | 36 | #define VERSION "0.1" |
@@ -560,6 +562,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); | |||
560 | * The device driver must call this function when one or many nfc targets | 562 | * The device driver must call this function when one or many nfc targets |
561 | * are found. After calling this function, the device driver must stop | 563 | * are found. After calling this function, the device driver must stop |
562 | * polling for targets. | 564 | * polling for targets. |
565 | * NOTE: This function can be called with targets=NULL and n_targets=0 to | ||
566 | * notify a driver error, meaning that the polling operation cannot complete. | ||
563 | * IMPORTANT: this function must not be called from an atomic context. | 567 | * IMPORTANT: this function must not be called from an atomic context. |
564 | * In addition, it must also not be called from a context that would prevent | 568 | * In addition, it must also not be called from a context that would prevent |
565 | * the NFC Core to call other nfc ops entry point concurrently. | 569 | * the NFC Core to call other nfc ops entry point concurrently. |
@@ -571,23 +575,33 @@ int nfc_targets_found(struct nfc_dev *dev, | |||
571 | 575 | ||
572 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); | 576 | pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); |
573 | 577 | ||
574 | dev->polling = false; | ||
575 | |||
576 | for (i = 0; i < n_targets; i++) | 578 | for (i = 0; i < n_targets; i++) |
577 | targets[i].idx = dev->target_next_idx++; | 579 | targets[i].idx = dev->target_next_idx++; |
578 | 580 | ||
579 | device_lock(&dev->dev); | 581 | device_lock(&dev->dev); |
580 | 582 | ||
583 | if (dev->polling == false) { | ||
584 | device_unlock(&dev->dev); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | dev->polling = false; | ||
589 | |||
581 | dev->targets_generation++; | 590 | dev->targets_generation++; |
582 | 591 | ||
583 | kfree(dev->targets); | 592 | kfree(dev->targets); |
584 | dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), | 593 | dev->targets = NULL; |
585 | GFP_ATOMIC); | ||
586 | 594 | ||
587 | if (!dev->targets) { | 595 | if (targets) { |
588 | dev->n_targets = 0; | 596 | dev->targets = kmemdup(targets, |
589 | device_unlock(&dev->dev); | 597 | n_targets * sizeof(struct nfc_target), |
590 | return -ENOMEM; | 598 | GFP_ATOMIC); |
599 | |||
600 | if (!dev->targets) { | ||
601 | dev->n_targets = 0; | ||
602 | device_unlock(&dev->dev); | ||
603 | return -ENOMEM; | ||
604 | } | ||
591 | } | 605 | } |
592 | 606 | ||
593 | dev->n_targets = n_targets; | 607 | dev->n_targets = n_targets; |
@@ -651,6 +665,12 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) | |||
651 | } | 665 | } |
652 | EXPORT_SYMBOL(nfc_target_lost); | 666 | EXPORT_SYMBOL(nfc_target_lost); |
653 | 667 | ||
668 | inline void nfc_driver_failure(struct nfc_dev *dev, int err) | ||
669 | { | ||
670 | nfc_targets_found(dev, NULL, 0); | ||
671 | } | ||
672 | EXPORT_SYMBOL(nfc_driver_failure); | ||
673 | |||
654 | static void nfc_release(struct device *d) | 674 | static void nfc_release(struct device *d) |
655 | { | 675 | { |
656 | struct nfc_dev *dev = to_nfc_dev(d); | 676 | struct nfc_dev *dev = to_nfc_dev(d); |
@@ -906,3 +926,5 @@ MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); | |||
906 | MODULE_DESCRIPTION("NFC Core ver " VERSION); | 926 | MODULE_DESCRIPTION("NFC Core ver " VERSION); |
907 | MODULE_VERSION(VERSION); | 927 | MODULE_VERSION(VERSION); |
908 | MODULE_LICENSE("GPL"); | 928 | MODULE_LICENSE("GPL"); |
929 | MODULE_ALIAS_NETPROTO(PF_NFC); | ||
930 | MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME); | ||
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 8729abf5f18b..46362ef979db 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c | |||
@@ -28,26 +28,14 @@ | |||
28 | 28 | ||
29 | #include "hci.h" | 29 | #include "hci.h" |
30 | 30 | ||
31 | static int nfc_hci_result_to_errno(u8 result) | 31 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, |
32 | { | ||
33 | switch (result) { | ||
34 | case NFC_HCI_ANY_OK: | ||
35 | return 0; | ||
36 | case NFC_HCI_ANY_E_TIMEOUT: | ||
37 | return -ETIMEDOUT; | ||
38 | default: | ||
39 | return -1; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, u8 result, | ||
44 | struct sk_buff *skb, void *cb_data) | 32 | struct sk_buff *skb, void *cb_data) |
45 | { | 33 | { |
46 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; | 34 | struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; |
47 | 35 | ||
48 | pr_debug("HCI Cmd completed with HCI result=%d\n", result); | 36 | pr_debug("HCI Cmd completed with result=%d\n", err); |
49 | 37 | ||
50 | hcp_ew->exec_result = nfc_hci_result_to_errno(result); | 38 | hcp_ew->exec_result = err; |
51 | if (hcp_ew->exec_result == 0) | 39 | if (hcp_ew->exec_result == 0) |
52 | hcp_ew->result_skb = skb; | 40 | hcp_ew->result_skb = skb; |
53 | else | 41 | else |
@@ -311,9 +299,9 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev) | |||
311 | } | 299 | } |
312 | EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); | 300 | EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); |
313 | 301 | ||
314 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | 302 | int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, |
303 | u8 pipe) | ||
315 | { | 304 | { |
316 | u8 pipe = NFC_HCI_INVALID_PIPE; | ||
317 | bool pipe_created = false; | 305 | bool pipe_created = false; |
318 | int r; | 306 | int r; |
319 | 307 | ||
@@ -322,6 +310,9 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | |||
322 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) | 310 | if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) |
323 | return -EADDRINUSE; | 311 | return -EADDRINUSE; |
324 | 312 | ||
313 | if (pipe != NFC_HCI_INVALID_PIPE) | ||
314 | goto pipe_is_open; | ||
315 | |||
325 | switch (dest_gate) { | 316 | switch (dest_gate) { |
326 | case NFC_HCI_LINK_MGMT_GATE: | 317 | case NFC_HCI_LINK_MGMT_GATE: |
327 | pipe = NFC_HCI_LINK_MGMT_PIPE; | 318 | pipe = NFC_HCI_LINK_MGMT_PIPE; |
@@ -347,6 +338,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) | |||
347 | return r; | 338 | return r; |
348 | } | 339 | } |
349 | 340 | ||
341 | pipe_is_open: | ||
350 | hdev->gate2pipe[dest_gate] = pipe; | 342 | hdev->gate2pipe[dest_gate] = pipe; |
351 | 343 | ||
352 | return 0; | 344 | return 0; |
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index a8b0b71e8f86..36717cebfbb6 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c | |||
@@ -32,6 +32,18 @@ | |||
32 | /* Largest headroom needed for outgoing HCI commands */ | 32 | /* Largest headroom needed for outgoing HCI commands */ |
33 | #define HCI_CMDS_HEADROOM 1 | 33 | #define HCI_CMDS_HEADROOM 1 |
34 | 34 | ||
35 | static int nfc_hci_result_to_errno(u8 result) | ||
36 | { | ||
37 | switch (result) { | ||
38 | case NFC_HCI_ANY_OK: | ||
39 | return 0; | ||
40 | case NFC_HCI_ANY_E_TIMEOUT: | ||
41 | return -ETIME; | ||
42 | default: | ||
43 | return -1; | ||
44 | } | ||
45 | } | ||
46 | |||
35 | static void nfc_hci_msg_tx_work(struct work_struct *work) | 47 | static void nfc_hci_msg_tx_work(struct work_struct *work) |
36 | { | 48 | { |
37 | struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, | 49 | struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, |
@@ -46,7 +58,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) | |||
46 | if (timer_pending(&hdev->cmd_timer) == 0) { | 58 | if (timer_pending(&hdev->cmd_timer) == 0) { |
47 | if (hdev->cmd_pending_msg->cb) | 59 | if (hdev->cmd_pending_msg->cb) |
48 | hdev->cmd_pending_msg->cb(hdev, | 60 | hdev->cmd_pending_msg->cb(hdev, |
49 | NFC_HCI_ANY_E_TIMEOUT, | 61 | -ETIME, |
50 | NULL, | 62 | NULL, |
51 | hdev-> | 63 | hdev-> |
52 | cmd_pending_msg-> | 64 | cmd_pending_msg-> |
@@ -71,8 +83,7 @@ next_msg: | |||
71 | kfree_skb(skb); | 83 | kfree_skb(skb); |
72 | skb_queue_purge(&msg->msg_frags); | 84 | skb_queue_purge(&msg->msg_frags); |
73 | if (msg->cb) | 85 | if (msg->cb) |
74 | msg->cb(hdev, NFC_HCI_ANY_E_NOK, NULL, | 86 | msg->cb(hdev, r, NULL, msg->cb_context); |
75 | msg->cb_context); | ||
76 | kfree(msg); | 87 | kfree(msg); |
77 | break; | 88 | break; |
78 | } | 89 | } |
@@ -116,20 +127,13 @@ static void nfc_hci_msg_rx_work(struct work_struct *work) | |||
116 | } | 127 | } |
117 | } | 128 | } |
118 | 129 | ||
119 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | 130 | static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, |
120 | struct sk_buff *skb) | 131 | struct sk_buff *skb) |
121 | { | 132 | { |
122 | mutex_lock(&hdev->msg_tx_mutex); | ||
123 | |||
124 | if (hdev->cmd_pending_msg == NULL) { | ||
125 | kfree_skb(skb); | ||
126 | goto exit; | ||
127 | } | ||
128 | |||
129 | del_timer_sync(&hdev->cmd_timer); | 133 | del_timer_sync(&hdev->cmd_timer); |
130 | 134 | ||
131 | if (hdev->cmd_pending_msg->cb) | 135 | if (hdev->cmd_pending_msg->cb) |
132 | hdev->cmd_pending_msg->cb(hdev, result, skb, | 136 | hdev->cmd_pending_msg->cb(hdev, err, skb, |
133 | hdev->cmd_pending_msg->cb_context); | 137 | hdev->cmd_pending_msg->cb_context); |
134 | else | 138 | else |
135 | kfree_skb(skb); | 139 | kfree_skb(skb); |
@@ -138,6 +142,19 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | |||
138 | hdev->cmd_pending_msg = NULL; | 142 | hdev->cmd_pending_msg = NULL; |
139 | 143 | ||
140 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); | 144 | queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); |
145 | } | ||
146 | |||
147 | void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, | ||
148 | struct sk_buff *skb) | ||
149 | { | ||
150 | mutex_lock(&hdev->msg_tx_mutex); | ||
151 | |||
152 | if (hdev->cmd_pending_msg == NULL) { | ||
153 | kfree_skb(skb); | ||
154 | goto exit; | ||
155 | } | ||
156 | |||
157 | __nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb); | ||
141 | 158 | ||
142 | exit: | 159 | exit: |
143 | mutex_unlock(&hdev->msg_tx_mutex); | 160 | mutex_unlock(&hdev->msg_tx_mutex); |
@@ -213,7 +230,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) | |||
213 | } | 230 | } |
214 | break; | 231 | break; |
215 | case NFC_HCI_RF_READER_B_GATE: | 232 | case NFC_HCI_RF_READER_B_GATE: |
216 | targets->supported_protocols = NFC_PROTO_ISO14443_MASK; | 233 | targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; |
217 | break; | 234 | break; |
218 | default: | 235 | default: |
219 | if (hdev->ops->target_from_gate) | 236 | if (hdev->ops->target_from_gate) |
@@ -298,15 +315,15 @@ static void nfc_hci_cmd_timeout(unsigned long data) | |||
298 | } | 315 | } |
299 | 316 | ||
300 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, | 317 | static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, |
301 | u8 gates[]) | 318 | struct nfc_hci_gate *gates) |
302 | { | 319 | { |
303 | int r; | 320 | int r; |
304 | u8 *p = gates; | ||
305 | while (gate_count--) { | 321 | while (gate_count--) { |
306 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, *p); | 322 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, |
323 | gates->gate, gates->pipe); | ||
307 | if (r < 0) | 324 | if (r < 0) |
308 | return r; | 325 | return r; |
309 | p++; | 326 | gates++; |
310 | } | 327 | } |
311 | 328 | ||
312 | return 0; | 329 | return 0; |
@@ -316,14 +333,13 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) | |||
316 | { | 333 | { |
317 | struct sk_buff *skb = NULL; | 334 | struct sk_buff *skb = NULL; |
318 | int r; | 335 | int r; |
319 | u8 hci_gates[] = { /* NFC_HCI_ADMIN_GATE MUST be first */ | 336 | |
320 | NFC_HCI_ADMIN_GATE, NFC_HCI_LOOPBACK_GATE, | 337 | if (hdev->init_data.gates[0].gate != NFC_HCI_ADMIN_GATE) |
321 | NFC_HCI_ID_MGMT_GATE, NFC_HCI_LINK_MGMT_GATE, | 338 | return -EPROTO; |
322 | NFC_HCI_RF_READER_B_GATE, NFC_HCI_RF_READER_A_GATE | ||
323 | }; | ||
324 | 339 | ||
325 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, | 340 | r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, |
326 | NFC_HCI_ADMIN_GATE); | 341 | hdev->init_data.gates[0].gate, |
342 | hdev->init_data.gates[0].pipe); | ||
327 | if (r < 0) | 343 | if (r < 0) |
328 | goto exit; | 344 | goto exit; |
329 | 345 | ||
@@ -351,10 +367,6 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) | |||
351 | if (r < 0) | 367 | if (r < 0) |
352 | goto exit; | 368 | goto exit; |
353 | 369 | ||
354 | r = hci_dev_connect_gates(hdev, sizeof(hci_gates), hci_gates); | ||
355 | if (r < 0) | ||
356 | goto disconnect_all; | ||
357 | |||
358 | r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, | 370 | r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, |
359 | hdev->init_data.gates); | 371 | hdev->init_data.gates); |
360 | if (r < 0) | 372 | if (r < 0) |
@@ -717,6 +729,27 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) | |||
717 | } | 729 | } |
718 | EXPORT_SYMBOL(nfc_hci_get_clientdata); | 730 | EXPORT_SYMBOL(nfc_hci_get_clientdata); |
719 | 731 | ||
732 | static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) | ||
733 | { | ||
734 | mutex_lock(&hdev->msg_tx_mutex); | ||
735 | |||
736 | if (hdev->cmd_pending_msg == NULL) { | ||
737 | nfc_driver_failure(hdev->ndev, err); | ||
738 | goto exit; | ||
739 | } | ||
740 | |||
741 | __nfc_hci_cmd_completion(hdev, err, NULL); | ||
742 | |||
743 | exit: | ||
744 | mutex_unlock(&hdev->msg_tx_mutex); | ||
745 | } | ||
746 | |||
747 | void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) | ||
748 | { | ||
749 | nfc_hci_failure(hdev, err); | ||
750 | } | ||
751 | EXPORT_SYMBOL(nfc_hci_driver_failure); | ||
752 | |||
720 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | 753 | void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
721 | { | 754 | { |
722 | struct hcp_packet *packet; | 755 | struct hcp_packet *packet; |
@@ -727,16 +760,6 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | |||
727 | struct sk_buff *frag_skb; | 760 | struct sk_buff *frag_skb; |
728 | int msg_len; | 761 | int msg_len; |
729 | 762 | ||
730 | if (skb == NULL) { | ||
731 | /* TODO ELa: lower layer had permanent failure, need to | ||
732 | * propagate that up | ||
733 | */ | ||
734 | |||
735 | skb_queue_purge(&hdev->rx_hcp_frags); | ||
736 | |||
737 | return; | ||
738 | } | ||
739 | |||
740 | packet = (struct hcp_packet *)skb->data; | 763 | packet = (struct hcp_packet *)skb->data; |
741 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { | 764 | if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { |
742 | skb_queue_tail(&hdev->rx_hcp_frags, skb); | 765 | skb_queue_tail(&hdev->rx_hcp_frags, skb); |
@@ -757,9 +780,8 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) | |||
757 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + | 780 | hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + |
758 | msg_len, GFP_KERNEL); | 781 | msg_len, GFP_KERNEL); |
759 | if (hcp_skb == NULL) { | 782 | if (hcp_skb == NULL) { |
760 | /* TODO ELa: cannot deliver HCP message. How to | 783 | nfc_hci_failure(hdev, -ENOMEM); |
761 | * propagate error up? | 784 | return; |
762 | */ | ||
763 | } | 785 | } |
764 | 786 | ||
765 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; | 787 | *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; |
diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index 45f2fe4fd486..fa9a21e92239 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h | |||
@@ -37,10 +37,11 @@ struct hcp_packet { | |||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * HCI command execution completion callback. | 39 | * HCI command execution completion callback. |
40 | * result will be one of the HCI response codes. | 40 | * result will be a standard linux error (may be converted from HCI response) |
41 | * skb contains the response data and must be disposed. | 41 | * skb contains the response data and must be disposed, or may be NULL if |
42 | * an error occured | ||
42 | */ | 43 | */ |
43 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, u8 result, | 44 | typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, |
44 | struct sk_buff *skb, void *cb_data); | 45 | struct sk_buff *skb, void *cb_data); |
45 | 46 | ||
46 | struct hcp_exec_waiter { | 47 | struct hcp_exec_waiter { |
@@ -131,9 +132,4 @@ void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, | |||
131 | #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a | 132 | #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a |
132 | #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b | 133 | #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b |
133 | 134 | ||
134 | /* Pipes */ | ||
135 | #define NFC_HCI_INVALID_PIPE 0x80 | ||
136 | #define NFC_HCI_LINK_MGMT_PIPE 0x00 | ||
137 | #define NFC_HCI_ADMIN_PIPE 0x01 | ||
138 | |||
139 | #endif /* __LOCAL_HCI_H */ | 135 | #endif /* __LOCAL_HCI_H */ |
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 6b836e6242b7..6f840c18c892 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c | |||
@@ -340,15 +340,6 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) | |||
340 | shdlc->state = SHDLC_CONNECTED; | 340 | shdlc->state = SHDLC_CONNECTED; |
341 | } else { | 341 | } else { |
342 | shdlc->state = SHDLC_DISCONNECTED; | 342 | shdlc->state = SHDLC_DISCONNECTED; |
343 | |||
344 | /* | ||
345 | * TODO: Could it be possible that there are pending | ||
346 | * executing commands that are waiting for connect to complete | ||
347 | * before they can be carried? As connect is a blocking | ||
348 | * operation, it would require that the userspace process can | ||
349 | * send commands on the same device from a second thread before | ||
350 | * the device is up. I don't think that is possible, is it? | ||
351 | */ | ||
352 | } | 343 | } |
353 | 344 | ||
354 | shdlc->connect_result = r; | 345 | shdlc->connect_result = r; |
@@ -413,12 +404,12 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, | |||
413 | r = nfc_shdlc_connect_send_ua(shdlc); | 404 | r = nfc_shdlc_connect_send_ua(shdlc); |
414 | nfc_shdlc_connect_complete(shdlc, r); | 405 | nfc_shdlc_connect_complete(shdlc, r); |
415 | } | 406 | } |
416 | } else if (shdlc->state > SHDLC_NEGOCIATING) { | 407 | } else if (shdlc->state == SHDLC_CONNECTED) { |
417 | /* | 408 | /* |
418 | * TODO: Chip wants to reset link | 409 | * Chip wants to reset link. This is unexpected and |
419 | * send ua, empty skb lists, reset counters | 410 | * unsupported. |
420 | * propagate info to HCI layer | ||
421 | */ | 411 | */ |
412 | shdlc->hard_fault = -ECONNRESET; | ||
422 | } | 413 | } |
423 | break; | 414 | break; |
424 | case U_FRAME_UA: | 415 | case U_FRAME_UA: |
@@ -523,10 +514,6 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) | |||
523 | 514 | ||
524 | r = shdlc->ops->xmit(shdlc, skb); | 515 | r = shdlc->ops->xmit(shdlc, skb); |
525 | if (r < 0) { | 516 | if (r < 0) { |
526 | /* | ||
527 | * TODO: Cannot send, shdlc machine is dead, we | ||
528 | * must propagate the information up to HCI. | ||
529 | */ | ||
530 | shdlc->hard_fault = r; | 517 | shdlc->hard_fault = r; |
531 | break; | 518 | break; |
532 | } | 519 | } |
@@ -590,6 +577,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
590 | skb_queue_purge(&shdlc->ack_pending_q); | 577 | skb_queue_purge(&shdlc->ack_pending_q); |
591 | break; | 578 | break; |
592 | case SHDLC_CONNECTING: | 579 | case SHDLC_CONNECTING: |
580 | if (shdlc->hard_fault) { | ||
581 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | ||
582 | break; | ||
583 | } | ||
584 | |||
593 | if (shdlc->connect_tries++ < 5) | 585 | if (shdlc->connect_tries++ < 5) |
594 | r = nfc_shdlc_connect_initiate(shdlc); | 586 | r = nfc_shdlc_connect_initiate(shdlc); |
595 | else | 587 | else |
@@ -610,6 +602,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
610 | } | 602 | } |
611 | 603 | ||
612 | nfc_shdlc_handle_rcv_queue(shdlc); | 604 | nfc_shdlc_handle_rcv_queue(shdlc); |
605 | |||
606 | if (shdlc->hard_fault) { | ||
607 | nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); | ||
608 | break; | ||
609 | } | ||
613 | break; | 610 | break; |
614 | case SHDLC_CONNECTED: | 611 | case SHDLC_CONNECTED: |
615 | nfc_shdlc_handle_rcv_queue(shdlc); | 612 | nfc_shdlc_handle_rcv_queue(shdlc); |
@@ -637,10 +634,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) | |||
637 | } | 634 | } |
638 | 635 | ||
639 | if (shdlc->hard_fault) { | 636 | if (shdlc->hard_fault) { |
640 | /* | 637 | nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); |
641 | * TODO: Handle hard_fault that occured during | ||
642 | * this invocation of the shdlc worker | ||
643 | */ | ||
644 | } | 638 | } |
645 | break; | 639 | break; |
646 | default: | 640 | default: |
@@ -923,8 +917,6 @@ void nfc_shdlc_free(struct nfc_shdlc *shdlc) | |||
923 | { | 917 | { |
924 | pr_debug("\n"); | 918 | pr_debug("\n"); |
925 | 919 | ||
926 | /* TODO: Check that this cannot be called while still in use */ | ||
927 | |||
928 | nfc_hci_unregister_device(shdlc->hdev); | 920 | nfc_hci_unregister_device(shdlc->hdev); |
929 | nfc_hci_free_device(shdlc->hdev); | 921 | nfc_hci_free_device(shdlc->hdev); |
930 | 922 | ||
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 5d503eeb15a1..82f0f7588b46 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -45,7 +45,7 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) | |||
45 | write_unlock(&l->lock); | 45 | write_unlock(&l->lock); |
46 | } | 46 | } |
47 | 47 | ||
48 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local) | 48 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) |
49 | { | 49 | { |
50 | struct sock *sk; | 50 | struct sock *sk; |
51 | struct hlist_node *node, *tmp; | 51 | struct hlist_node *node, *tmp; |
@@ -78,6 +78,11 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) | |||
78 | 78 | ||
79 | sock_orphan(accept_sk); | 79 | sock_orphan(accept_sk); |
80 | } | 80 | } |
81 | |||
82 | if (listen == true) { | ||
83 | release_sock(sk); | ||
84 | continue; | ||
85 | } | ||
81 | } | 86 | } |
82 | 87 | ||
83 | sk->sk_state = LLCP_CLOSED; | 88 | sk->sk_state = LLCP_CLOSED; |
@@ -106,7 +111,7 @@ static void local_release(struct kref *ref) | |||
106 | local = container_of(ref, struct nfc_llcp_local, ref); | 111 | local = container_of(ref, struct nfc_llcp_local, ref); |
107 | 112 | ||
108 | list_del(&local->list); | 113 | list_del(&local->list); |
109 | nfc_llcp_socket_release(local); | 114 | nfc_llcp_socket_release(local, false); |
110 | del_timer_sync(&local->link_timer); | 115 | del_timer_sync(&local->link_timer); |
111 | skb_queue_purge(&local->tx_queue); | 116 | skb_queue_purge(&local->tx_queue); |
112 | destroy_workqueue(local->tx_wq); | 117 | destroy_workqueue(local->tx_wq); |
@@ -118,23 +123,48 @@ static void local_release(struct kref *ref) | |||
118 | 123 | ||
119 | int nfc_llcp_local_put(struct nfc_llcp_local *local) | 124 | int nfc_llcp_local_put(struct nfc_llcp_local *local) |
120 | { | 125 | { |
121 | WARN_ON(local == NULL); | ||
122 | |||
123 | if (local == NULL) | 126 | if (local == NULL) |
124 | return 0; | 127 | return 0; |
125 | 128 | ||
126 | return kref_put(&local->ref, local_release); | 129 | return kref_put(&local->ref, local_release); |
127 | } | 130 | } |
128 | 131 | ||
129 | static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) | 132 | static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, |
133 | u8 ssap, u8 dsap) | ||
130 | { | 134 | { |
131 | mutex_lock(&local->sdp_lock); | 135 | struct sock *sk; |
136 | struct hlist_node *node; | ||
137 | struct nfc_llcp_sock *llcp_sock; | ||
132 | 138 | ||
133 | local->local_wks = 0; | 139 | pr_debug("ssap dsap %d %d\n", ssap, dsap); |
134 | local->local_sdp = 0; | ||
135 | local->local_sap = 0; | ||
136 | 140 | ||
137 | mutex_unlock(&local->sdp_lock); | 141 | if (ssap == 0 && dsap == 0) |
142 | return NULL; | ||
143 | |||
144 | read_lock(&local->sockets.lock); | ||
145 | |||
146 | llcp_sock = NULL; | ||
147 | |||
148 | sk_for_each(sk, node, &local->sockets.head) { | ||
149 | llcp_sock = nfc_llcp_sock(sk); | ||
150 | |||
151 | if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | read_unlock(&local->sockets.lock); | ||
156 | |||
157 | if (llcp_sock == NULL) | ||
158 | return NULL; | ||
159 | |||
160 | sock_hold(&llcp_sock->sk); | ||
161 | |||
162 | return llcp_sock; | ||
163 | } | ||
164 | |||
165 | static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) | ||
166 | { | ||
167 | sock_put(&sock->sk); | ||
138 | } | 168 | } |
139 | 169 | ||
140 | static void nfc_llcp_timeout_work(struct work_struct *work) | 170 | static void nfc_llcp_timeout_work(struct work_struct *work) |
@@ -197,6 +227,51 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) | |||
197 | return -EINVAL; | 227 | return -EINVAL; |
198 | } | 228 | } |
199 | 229 | ||
230 | static | ||
231 | struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, | ||
232 | u8 *sn, size_t sn_len) | ||
233 | { | ||
234 | struct sock *sk; | ||
235 | struct hlist_node *node; | ||
236 | struct nfc_llcp_sock *llcp_sock, *tmp_sock; | ||
237 | |||
238 | pr_debug("sn %zd %p\n", sn_len, sn); | ||
239 | |||
240 | if (sn == NULL || sn_len == 0) | ||
241 | return NULL; | ||
242 | |||
243 | read_lock(&local->sockets.lock); | ||
244 | |||
245 | llcp_sock = NULL; | ||
246 | |||
247 | sk_for_each(sk, node, &local->sockets.head) { | ||
248 | tmp_sock = nfc_llcp_sock(sk); | ||
249 | |||
250 | pr_debug("llcp sock %p\n", tmp_sock); | ||
251 | |||
252 | if (tmp_sock->sk.sk_state != LLCP_LISTEN) | ||
253 | continue; | ||
254 | |||
255 | if (tmp_sock->service_name == NULL || | ||
256 | tmp_sock->service_name_len == 0) | ||
257 | continue; | ||
258 | |||
259 | if (tmp_sock->service_name_len != sn_len) | ||
260 | continue; | ||
261 | |||
262 | if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) { | ||
263 | llcp_sock = tmp_sock; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | read_unlock(&local->sockets.lock); | ||
269 | |||
270 | pr_debug("Found llcp sock %p\n", llcp_sock); | ||
271 | |||
272 | return llcp_sock; | ||
273 | } | ||
274 | |||
200 | u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | 275 | u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, |
201 | struct nfc_llcp_sock *sock) | 276 | struct nfc_llcp_sock *sock) |
202 | { | 277 | { |
@@ -223,41 +298,26 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, | |||
223 | } | 298 | } |
224 | 299 | ||
225 | /* | 300 | /* |
226 | * This is not a well known service, | 301 | * Check if there already is a non WKS socket bound |
227 | * we should try to find a local SDP free spot | 302 | * to this service name. |
228 | */ | 303 | */ |
229 | ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); | 304 | if (nfc_llcp_sock_from_sn(local, sock->service_name, |
230 | if (ssap == LLCP_SDP_NUM_SAP) { | 305 | sock->service_name_len) != NULL) { |
231 | mutex_unlock(&local->sdp_lock); | 306 | mutex_unlock(&local->sdp_lock); |
232 | 307 | ||
233 | return LLCP_SAP_MAX; | 308 | return LLCP_SAP_MAX; |
234 | } | 309 | } |
235 | 310 | ||
236 | pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); | ||
237 | |||
238 | set_bit(ssap, &local->local_sdp); | ||
239 | mutex_unlock(&local->sdp_lock); | 311 | mutex_unlock(&local->sdp_lock); |
240 | 312 | ||
241 | return LLCP_WKS_NUM_SAP + ssap; | 313 | return LLCP_SDP_UNBOUND; |
242 | |||
243 | } else if (sock->ssap != 0) { | ||
244 | if (sock->ssap < LLCP_WKS_NUM_SAP) { | ||
245 | if (!test_bit(sock->ssap, &local->local_wks)) { | ||
246 | set_bit(sock->ssap, &local->local_wks); | ||
247 | mutex_unlock(&local->sdp_lock); | ||
248 | |||
249 | return sock->ssap; | ||
250 | } | ||
251 | 314 | ||
252 | } else if (sock->ssap < LLCP_SDP_NUM_SAP) { | 315 | } else if (sock->ssap != 0 && sock->ssap < LLCP_WKS_NUM_SAP) { |
253 | if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP, | 316 | if (!test_bit(sock->ssap, &local->local_wks)) { |
254 | &local->local_sdp)) { | 317 | set_bit(sock->ssap, &local->local_wks); |
255 | set_bit(sock->ssap - LLCP_WKS_NUM_SAP, | 318 | mutex_unlock(&local->sdp_lock); |
256 | &local->local_sdp); | ||
257 | mutex_unlock(&local->sdp_lock); | ||
258 | 319 | ||
259 | return sock->ssap; | 320 | return sock->ssap; |
260 | } | ||
261 | } | 321 | } |
262 | } | 322 | } |
263 | 323 | ||
@@ -294,8 +354,34 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) | |||
294 | local_ssap = ssap; | 354 | local_ssap = ssap; |
295 | sdp = &local->local_wks; | 355 | sdp = &local->local_wks; |
296 | } else if (ssap < LLCP_LOCAL_NUM_SAP) { | 356 | } else if (ssap < LLCP_LOCAL_NUM_SAP) { |
357 | atomic_t *client_cnt; | ||
358 | |||
297 | local_ssap = ssap - LLCP_WKS_NUM_SAP; | 359 | local_ssap = ssap - LLCP_WKS_NUM_SAP; |
298 | sdp = &local->local_sdp; | 360 | sdp = &local->local_sdp; |
361 | client_cnt = &local->local_sdp_cnt[local_ssap]; | ||
362 | |||
363 | pr_debug("%d clients\n", atomic_read(client_cnt)); | ||
364 | |||
365 | mutex_lock(&local->sdp_lock); | ||
366 | |||
367 | if (atomic_dec_and_test(client_cnt)) { | ||
368 | struct nfc_llcp_sock *l_sock; | ||
369 | |||
370 | pr_debug("No more clients for SAP %d\n", ssap); | ||
371 | |||
372 | clear_bit(local_ssap, sdp); | ||
373 | |||
374 | /* Find the listening sock and set it back to UNBOUND */ | ||
375 | l_sock = nfc_llcp_sock_get(local, ssap, LLCP_SAP_SDP); | ||
376 | if (l_sock) { | ||
377 | l_sock->ssap = LLCP_SDP_UNBOUND; | ||
378 | nfc_llcp_sock_put(l_sock); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | mutex_unlock(&local->sdp_lock); | ||
383 | |||
384 | return; | ||
299 | } else if (ssap < LLCP_MAX_SAP) { | 385 | } else if (ssap < LLCP_MAX_SAP) { |
300 | local_ssap = ssap - LLCP_LOCAL_NUM_SAP; | 386 | local_ssap = ssap - LLCP_LOCAL_NUM_SAP; |
301 | sdp = &local->local_sap; | 387 | sdp = &local->local_sap; |
@@ -310,19 +396,26 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) | |||
310 | mutex_unlock(&local->sdp_lock); | 396 | mutex_unlock(&local->sdp_lock); |
311 | } | 397 | } |
312 | 398 | ||
313 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | 399 | static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local) |
314 | { | 400 | { |
315 | struct nfc_llcp_local *local; | 401 | u8 ssap; |
316 | 402 | ||
317 | local = nfc_llcp_find_local(dev); | 403 | mutex_lock(&local->sdp_lock); |
318 | if (local == NULL) { | 404 | |
319 | *general_bytes_len = 0; | 405 | ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); |
320 | return NULL; | 406 | if (ssap == LLCP_SDP_NUM_SAP) { |
407 | mutex_unlock(&local->sdp_lock); | ||
408 | |||
409 | return LLCP_SAP_MAX; | ||
321 | } | 410 | } |
322 | 411 | ||
323 | *general_bytes_len = local->gb_len; | 412 | pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); |
324 | 413 | ||
325 | return local->gb; | 414 | set_bit(ssap, &local->local_sdp); |
415 | |||
416 | mutex_unlock(&local->sdp_lock); | ||
417 | |||
418 | return LLCP_WKS_NUM_SAP + ssap; | ||
326 | } | 419 | } |
327 | 420 | ||
328 | static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | 421 | static int nfc_llcp_build_gb(struct nfc_llcp_local *local) |
@@ -386,6 +479,23 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) | |||
386 | return 0; | 479 | return 0; |
387 | } | 480 | } |
388 | 481 | ||
482 | u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) | ||
483 | { | ||
484 | struct nfc_llcp_local *local; | ||
485 | |||
486 | local = nfc_llcp_find_local(dev); | ||
487 | if (local == NULL) { | ||
488 | *general_bytes_len = 0; | ||
489 | return NULL; | ||
490 | } | ||
491 | |||
492 | nfc_llcp_build_gb(local); | ||
493 | |||
494 | *general_bytes_len = local->gb_len; | ||
495 | |||
496 | return local->gb; | ||
497 | } | ||
498 | |||
389 | int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) | 499 | int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) |
390 | { | 500 | { |
391 | struct nfc_llcp_local *local = nfc_llcp_find_local(dev); | 501 | struct nfc_llcp_local *local = nfc_llcp_find_local(dev); |
@@ -509,74 +619,12 @@ out: | |||
509 | return llcp_sock; | 619 | return llcp_sock; |
510 | } | 620 | } |
511 | 621 | ||
512 | static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, | ||
513 | u8 ssap, u8 dsap) | ||
514 | { | ||
515 | struct sock *sk; | ||
516 | struct hlist_node *node; | ||
517 | struct nfc_llcp_sock *llcp_sock; | ||
518 | |||
519 | pr_debug("ssap dsap %d %d\n", ssap, dsap); | ||
520 | |||
521 | if (ssap == 0 && dsap == 0) | ||
522 | return NULL; | ||
523 | |||
524 | read_lock(&local->sockets.lock); | ||
525 | |||
526 | llcp_sock = NULL; | ||
527 | |||
528 | sk_for_each(sk, node, &local->sockets.head) { | ||
529 | llcp_sock = nfc_llcp_sock(sk); | ||
530 | |||
531 | if (llcp_sock->ssap == ssap && | ||
532 | llcp_sock->dsap == dsap) | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | read_unlock(&local->sockets.lock); | ||
537 | |||
538 | if (llcp_sock == NULL) | ||
539 | return NULL; | ||
540 | |||
541 | sock_hold(&llcp_sock->sk); | ||
542 | |||
543 | return llcp_sock; | ||
544 | } | ||
545 | |||
546 | static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, | 622 | static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, |
547 | u8 *sn, size_t sn_len) | 623 | u8 *sn, size_t sn_len) |
548 | { | 624 | { |
549 | struct sock *sk; | ||
550 | struct hlist_node *node; | ||
551 | struct nfc_llcp_sock *llcp_sock; | 625 | struct nfc_llcp_sock *llcp_sock; |
552 | 626 | ||
553 | pr_debug("sn %zd\n", sn_len); | 627 | llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len); |
554 | |||
555 | if (sn == NULL || sn_len == 0) | ||
556 | return NULL; | ||
557 | |||
558 | read_lock(&local->sockets.lock); | ||
559 | |||
560 | llcp_sock = NULL; | ||
561 | |||
562 | sk_for_each(sk, node, &local->sockets.head) { | ||
563 | llcp_sock = nfc_llcp_sock(sk); | ||
564 | |||
565 | if (llcp_sock->sk.sk_state != LLCP_LISTEN) | ||
566 | continue; | ||
567 | |||
568 | if (llcp_sock->service_name == NULL || | ||
569 | llcp_sock->service_name_len == 0) | ||
570 | continue; | ||
571 | |||
572 | if (llcp_sock->service_name_len != sn_len) | ||
573 | continue; | ||
574 | |||
575 | if (memcmp(sn, llcp_sock->service_name, sn_len) == 0) | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | read_unlock(&local->sockets.lock); | ||
580 | 628 | ||
581 | if (llcp_sock == NULL) | 629 | if (llcp_sock == NULL) |
582 | return NULL; | 630 | return NULL; |
@@ -586,11 +634,6 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, | |||
586 | return llcp_sock; | 634 | return llcp_sock; |
587 | } | 635 | } |
588 | 636 | ||
589 | static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) | ||
590 | { | ||
591 | sock_put(&sock->sk); | ||
592 | } | ||
593 | |||
594 | static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) | 637 | static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) |
595 | { | 638 | { |
596 | u8 *tlv = &skb->data[2], type, length; | 639 | u8 *tlv = &skb->data[2], type, length; |
@@ -662,6 +705,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
662 | goto fail; | 705 | goto fail; |
663 | } | 706 | } |
664 | 707 | ||
708 | if (sock->ssap == LLCP_SDP_UNBOUND) { | ||
709 | u8 ssap = nfc_llcp_reserve_sdp_ssap(local); | ||
710 | |||
711 | pr_debug("First client, reserving %d\n", ssap); | ||
712 | |||
713 | if (ssap == LLCP_SAP_MAX) { | ||
714 | reason = LLCP_DM_REJ; | ||
715 | release_sock(&sock->sk); | ||
716 | sock_put(&sock->sk); | ||
717 | goto fail; | ||
718 | } | ||
719 | |||
720 | sock->ssap = ssap; | ||
721 | } | ||
722 | |||
665 | new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); | 723 | new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); |
666 | if (new_sk == NULL) { | 724 | if (new_sk == NULL) { |
667 | reason = LLCP_DM_REJ; | 725 | reason = LLCP_DM_REJ; |
@@ -675,9 +733,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
675 | new_sock->local = nfc_llcp_local_get(local); | 733 | new_sock->local = nfc_llcp_local_get(local); |
676 | new_sock->miu = local->remote_miu; | 734 | new_sock->miu = local->remote_miu; |
677 | new_sock->nfc_protocol = sock->nfc_protocol; | 735 | new_sock->nfc_protocol = sock->nfc_protocol; |
678 | new_sock->ssap = sock->ssap; | ||
679 | new_sock->dsap = ssap; | 736 | new_sock->dsap = ssap; |
737 | new_sock->target_idx = local->target_idx; | ||
680 | new_sock->parent = parent; | 738 | new_sock->parent = parent; |
739 | new_sock->ssap = sock->ssap; | ||
740 | if (sock->ssap < LLCP_LOCAL_NUM_SAP && sock->ssap >= LLCP_WKS_NUM_SAP) { | ||
741 | atomic_t *client_count; | ||
742 | |||
743 | pr_debug("reserved_ssap %d for %p\n", sock->ssap, new_sock); | ||
744 | |||
745 | client_count = | ||
746 | &local->local_sdp_cnt[sock->ssap - LLCP_WKS_NUM_SAP]; | ||
747 | |||
748 | atomic_inc(client_count); | ||
749 | new_sock->reserved_ssap = sock->ssap; | ||
750 | } | ||
681 | 751 | ||
682 | nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], | 752 | nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], |
683 | skb->len - LLCP_HEADER_SIZE); | 753 | skb->len - LLCP_HEADER_SIZE); |
@@ -886,6 +956,45 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) | |||
886 | nfc_llcp_sock_put(llcp_sock); | 956 | nfc_llcp_sock_put(llcp_sock); |
887 | } | 957 | } |
888 | 958 | ||
959 | static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb) | ||
960 | { | ||
961 | struct nfc_llcp_sock *llcp_sock; | ||
962 | struct sock *sk; | ||
963 | u8 dsap, ssap, reason; | ||
964 | |||
965 | dsap = nfc_llcp_dsap(skb); | ||
966 | ssap = nfc_llcp_ssap(skb); | ||
967 | reason = skb->data[2]; | ||
968 | |||
969 | pr_debug("%d %d reason %d\n", ssap, dsap, reason); | ||
970 | |||
971 | switch (reason) { | ||
972 | case LLCP_DM_NOBOUND: | ||
973 | case LLCP_DM_REJ: | ||
974 | llcp_sock = nfc_llcp_connecting_sock_get(local, dsap); | ||
975 | break; | ||
976 | |||
977 | default: | ||
978 | llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); | ||
979 | break; | ||
980 | } | ||
981 | |||
982 | if (llcp_sock == NULL) { | ||
983 | pr_err("Invalid DM\n"); | ||
984 | return; | ||
985 | } | ||
986 | |||
987 | sk = &llcp_sock->sk; | ||
988 | |||
989 | sk->sk_err = ENXIO; | ||
990 | sk->sk_state = LLCP_CLOSED; | ||
991 | sk->sk_state_change(sk); | ||
992 | |||
993 | nfc_llcp_sock_put(llcp_sock); | ||
994 | |||
995 | return; | ||
996 | } | ||
997 | |||
889 | static void nfc_llcp_rx_work(struct work_struct *work) | 998 | static void nfc_llcp_rx_work(struct work_struct *work) |
890 | { | 999 | { |
891 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 1000 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, |
@@ -929,6 +1038,11 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
929 | nfc_llcp_recv_cc(local, skb); | 1038 | nfc_llcp_recv_cc(local, skb); |
930 | break; | 1039 | break; |
931 | 1040 | ||
1041 | case LLCP_PDU_DM: | ||
1042 | pr_debug("DM\n"); | ||
1043 | nfc_llcp_recv_dm(local, skb); | ||
1044 | break; | ||
1045 | |||
932 | case LLCP_PDU_I: | 1046 | case LLCP_PDU_I: |
933 | case LLCP_PDU_RR: | 1047 | case LLCP_PDU_RR: |
934 | case LLCP_PDU_RNR: | 1048 | case LLCP_PDU_RNR: |
@@ -985,10 +1099,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) | |||
985 | if (local == NULL) | 1099 | if (local == NULL) |
986 | return; | 1100 | return; |
987 | 1101 | ||
988 | nfc_llcp_clear_sdp(local); | ||
989 | |||
990 | /* Close and purge all existing sockets */ | 1102 | /* Close and purge all existing sockets */ |
991 | nfc_llcp_socket_release(local); | 1103 | nfc_llcp_socket_release(local, true); |
992 | } | 1104 | } |
993 | 1105 | ||
994 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, | 1106 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 7286c86982ff..83b8bba5a280 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -37,6 +37,7 @@ enum llcp_state { | |||
37 | #define LLCP_LOCAL_NUM_SAP 32 | 37 | #define LLCP_LOCAL_NUM_SAP 32 |
38 | #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) | 38 | #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) |
39 | #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) | 39 | #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) |
40 | #define LLCP_SDP_UNBOUND (LLCP_MAX_SAP + 1) | ||
40 | 41 | ||
41 | struct nfc_llcp_sock; | 42 | struct nfc_llcp_sock; |
42 | 43 | ||
@@ -69,6 +70,7 @@ struct nfc_llcp_local { | |||
69 | unsigned long local_wks; /* Well known services */ | 70 | unsigned long local_wks; /* Well known services */ |
70 | unsigned long local_sdp; /* Local services */ | 71 | unsigned long local_sdp; /* Local services */ |
71 | unsigned long local_sap; /* Local SAPs, not available for discovery */ | 72 | unsigned long local_sap; /* Local SAPs, not available for discovery */ |
73 | atomic_t local_sdp_cnt[LLCP_SDP_NUM_SAP]; | ||
72 | 74 | ||
73 | /* local */ | 75 | /* local */ |
74 | u8 gb[NFC_MAX_GT_LEN]; | 76 | u8 gb[NFC_MAX_GT_LEN]; |
@@ -113,6 +115,9 @@ struct nfc_llcp_sock { | |||
113 | /* Is the remote peer ready to receive */ | 115 | /* Is the remote peer ready to receive */ |
114 | u8 remote_ready; | 116 | u8 remote_ready; |
115 | 117 | ||
118 | /* Reserved source SAP */ | ||
119 | u8 reserved_ssap; | ||
120 | |||
116 | struct sk_buff_head tx_queue; | 121 | struct sk_buff_head tx_queue; |
117 | struct sk_buff_head tx_pending_queue; | 122 | struct sk_buff_head tx_pending_queue; |
118 | struct sk_buff_head tx_backlog_queue; | 123 | struct sk_buff_head tx_backlog_queue; |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 05ca5a680071..ddeb9aa398f0 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -78,11 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
78 | struct sockaddr_nfc_llcp llcp_addr; | 78 | struct sockaddr_nfc_llcp llcp_addr; |
79 | int len, ret = 0; | 79 | int len, ret = 0; |
80 | 80 | ||
81 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
82 | |||
83 | if (!addr || addr->sa_family != AF_NFC) | 81 | if (!addr || addr->sa_family != AF_NFC) |
84 | return -EINVAL; | 82 | return -EINVAL; |
85 | 83 | ||
84 | pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); | ||
85 | |||
86 | memset(&llcp_addr, 0, sizeof(llcp_addr)); | 86 | memset(&llcp_addr, 0, sizeof(llcp_addr)); |
87 | len = min_t(unsigned int, sizeof(llcp_addr), alen); | 87 | len = min_t(unsigned int, sizeof(llcp_addr), alen); |
88 | memcpy(&llcp_addr, addr, len); | 88 | memcpy(&llcp_addr, addr, len); |
@@ -121,8 +121,12 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) | |||
121 | GFP_KERNEL); | 121 | GFP_KERNEL); |
122 | 122 | ||
123 | llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); | 123 | llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); |
124 | if (llcp_sock->ssap == LLCP_MAX_SAP) | 124 | if (llcp_sock->ssap == LLCP_SAP_MAX) { |
125 | ret = -EADDRINUSE; | ||
125 | goto put_dev; | 126 | goto put_dev; |
127 | } | ||
128 | |||
129 | llcp_sock->reserved_ssap = llcp_sock->ssap; | ||
126 | 130 | ||
127 | nfc_llcp_sock_link(&local->sockets, sk); | 131 | nfc_llcp_sock_link(&local->sockets, sk); |
128 | 132 | ||
@@ -283,22 +287,28 @@ error: | |||
283 | return ret; | 287 | return ret; |
284 | } | 288 | } |
285 | 289 | ||
286 | static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, | 290 | static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, |
287 | int *len, int peer) | 291 | int *len, int peer) |
288 | { | 292 | { |
289 | struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr; | ||
290 | struct sock *sk = sock->sk; | 293 | struct sock *sk = sock->sk; |
291 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 294 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
295 | DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr); | ||
292 | 296 | ||
293 | pr_debug("%p\n", sk); | 297 | if (llcp_sock == NULL || llcp_sock->dev == NULL) |
298 | return -EBADFD; | ||
299 | |||
300 | pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, | ||
301 | llcp_sock->dsap, llcp_sock->ssap); | ||
294 | 302 | ||
295 | if (llcp_sock == NULL || llcp_sock->dev == NULL) | 303 | if (llcp_sock == NULL || llcp_sock->dev == NULL) |
296 | return -EBADFD; | 304 | return -EBADFD; |
297 | 305 | ||
298 | addr->sa_family = AF_NFC; | 306 | uaddr->sa_family = AF_NFC; |
307 | |||
299 | *len = sizeof(struct sockaddr_nfc_llcp); | 308 | *len = sizeof(struct sockaddr_nfc_llcp); |
300 | 309 | ||
301 | llcp_addr->dev_idx = llcp_sock->dev->idx; | 310 | llcp_addr->dev_idx = llcp_sock->dev->idx; |
311 | llcp_addr->target_idx = llcp_sock->target_idx; | ||
302 | llcp_addr->dsap = llcp_sock->dsap; | 312 | llcp_addr->dsap = llcp_sock->dsap; |
303 | llcp_addr->ssap = llcp_sock->ssap; | 313 | llcp_addr->ssap = llcp_sock->ssap; |
304 | llcp_addr->service_name_len = llcp_sock->service_name_len; | 314 | llcp_addr->service_name_len = llcp_sock->service_name_len; |
@@ -406,7 +416,8 @@ static int llcp_sock_release(struct socket *sock) | |||
406 | } | 416 | } |
407 | } | 417 | } |
408 | 418 | ||
409 | nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); | 419 | if (llcp_sock->reserved_ssap < LLCP_SAP_MAX) |
420 | nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); | ||
410 | 421 | ||
411 | release_sock(sk); | 422 | release_sock(sk); |
412 | 423 | ||
@@ -486,6 +497,9 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, | |||
486 | ret = -ENOMEM; | 497 | ret = -ENOMEM; |
487 | goto put_dev; | 498 | goto put_dev; |
488 | } | 499 | } |
500 | |||
501 | llcp_sock->reserved_ssap = llcp_sock->ssap; | ||
502 | |||
489 | if (addr->service_name_len == 0) | 503 | if (addr->service_name_len == 0) |
490 | llcp_sock->dsap = addr->dsap; | 504 | llcp_sock->dsap = addr->dsap; |
491 | else | 505 | else |
@@ -687,6 +701,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) | |||
687 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; | 701 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; |
688 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; | 702 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; |
689 | llcp_sock->remote_ready = 1; | 703 | llcp_sock->remote_ready = 1; |
704 | llcp_sock->reserved_ssap = LLCP_SAP_MAX; | ||
690 | skb_queue_head_init(&llcp_sock->tx_queue); | 705 | skb_queue_head_init(&llcp_sock->tx_queue); |
691 | skb_queue_head_init(&llcp_sock->tx_pending_queue); | 706 | skb_queue_head_init(&llcp_sock->tx_pending_queue); |
692 | skb_queue_head_init(&llcp_sock->tx_backlog_queue); | 707 | skb_queue_head_init(&llcp_sock->tx_backlog_queue); |
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 766a02b1dfa1..5bb4da680427 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c | |||
@@ -194,7 +194,7 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) | |||
194 | } | 194 | } |
195 | 195 | ||
196 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && | 196 | if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && |
197 | (protocols & NFC_PROTO_ISO14443_MASK)) { | 197 | (protocols & NFC_PROTO_ISO14443_B_MASK)) { |
198 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = | 198 | cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = |
199 | NCI_NFC_B_PASSIVE_POLL_MODE; | 199 | NCI_NFC_B_PASSIVE_POLL_MODE; |
200 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; | 200 | cmd.disc_configs[cmd.num_disc_configs].frequency = 1; |
@@ -486,7 +486,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, | |||
486 | param.rf_protocol = NCI_RF_PROTOCOL_T2T; | 486 | param.rf_protocol = NCI_RF_PROTOCOL_T2T; |
487 | else if (protocol == NFC_PROTO_FELICA) | 487 | else if (protocol == NFC_PROTO_FELICA) |
488 | param.rf_protocol = NCI_RF_PROTOCOL_T3T; | 488 | param.rf_protocol = NCI_RF_PROTOCOL_T3T; |
489 | else if (protocol == NFC_PROTO_ISO14443) | 489 | else if (protocol == NFC_PROTO_ISO14443 || |
490 | protocol == NFC_PROTO_ISO14443_B) | ||
490 | param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; | 491 | param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; |
491 | else | 492 | else |
492 | param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; | 493 | param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; |
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 2ab196a9f228..af7a93b04393 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c | |||
@@ -170,7 +170,10 @@ static int nci_add_new_protocol(struct nci_dev *ndev, | |||
170 | if (rf_protocol == NCI_RF_PROTOCOL_T2T) | 170 | if (rf_protocol == NCI_RF_PROTOCOL_T2T) |
171 | protocol = NFC_PROTO_MIFARE_MASK; | 171 | protocol = NFC_PROTO_MIFARE_MASK; |
172 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) | 172 | else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) |
173 | protocol = NFC_PROTO_ISO14443_MASK; | 173 | if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) |
174 | protocol = NFC_PROTO_ISO14443_MASK; | ||
175 | else | ||
176 | protocol = NFC_PROTO_ISO14443_B_MASK; | ||
174 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) | 177 | else if (rf_protocol == NCI_RF_PROTOCOL_T3T) |
175 | protocol = NFC_PROTO_FELICA_MASK; | 178 | protocol = NFC_PROTO_FELICA_MASK; |
176 | else | 179 | else |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f4f07f9b61c0..4c51714ee741 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -634,6 +634,15 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) | |||
634 | if (!dev) | 634 | if (!dev) |
635 | return -ENODEV; | 635 | return -ENODEV; |
636 | 636 | ||
637 | device_lock(&dev->dev); | ||
638 | |||
639 | if (!dev->polling) { | ||
640 | device_unlock(&dev->dev); | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | device_unlock(&dev->dev); | ||
645 | |||
637 | mutex_lock(&dev->genl_data.genl_data_mutex); | 646 | mutex_lock(&dev->genl_data.genl_data_mutex); |
638 | 647 | ||
639 | if (dev->genl_data.poll_req_pid != info->snd_pid) { | 648 | if (dev->genl_data.poll_req_pid != info->snd_pid) { |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 55a28ab21db9..0f7e0d621ab0 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 | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.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/ap.c b/net/wireless/ap.c new file mode 100644 index 000000000000..fcc60d8dbefa --- /dev/null +++ b/net/wireless/ap.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/ieee80211.h> | ||
2 | #include <linux/export.h> | ||
3 | #include <net/cfg80211.h> | ||
4 | #include "nl80211.h" | ||
5 | #include "core.h" | ||
6 | |||
7 | |||
8 | static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
9 | struct net_device *dev) | ||
10 | { | ||
11 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
12 | int err; | ||
13 | |||
14 | ASSERT_WDEV_LOCK(wdev); | ||
15 | |||
16 | if (!rdev->ops->stop_ap) | ||
17 | return -EOPNOTSUPP; | ||
18 | |||
19 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
20 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
21 | return -EOPNOTSUPP; | ||
22 | |||
23 | if (!wdev->beacon_interval) | ||
24 | return -ENOENT; | ||
25 | |||
26 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
27 | if (!err) { | ||
28 | wdev->beacon_interval = 0; | ||
29 | wdev->channel = NULL; | ||
30 | } | ||
31 | |||
32 | return err; | ||
33 | } | ||
34 | |||
35 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
36 | struct net_device *dev) | ||
37 | { | ||
38 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
39 | int err; | ||
40 | |||
41 | wdev_lock(wdev); | ||
42 | err = __cfg80211_stop_ap(rdev, dev); | ||
43 | wdev_unlock(wdev); | ||
44 | |||
45 | return err; | ||
46 | } | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index c1999e45a07c..434c56b92c3c 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -82,13 +82,73 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | |||
82 | int freq, enum nl80211_channel_type chantype) | 82 | int freq, enum nl80211_channel_type chantype) |
83 | { | 83 | { |
84 | struct ieee80211_channel *chan; | 84 | struct ieee80211_channel *chan; |
85 | int err; | ||
85 | 86 | ||
86 | if (!rdev->ops->set_monitor_channel) | 87 | if (!rdev->ops->set_monitor_channel) |
87 | return -EOPNOTSUPP; | 88 | return -EOPNOTSUPP; |
89 | if (!cfg80211_has_monitors_only(rdev)) | ||
90 | return -EBUSY; | ||
88 | 91 | ||
89 | chan = rdev_freq_to_chan(rdev, freq, chantype); | 92 | chan = rdev_freq_to_chan(rdev, freq, chantype); |
90 | if (!chan) | 93 | if (!chan) |
91 | return -EINVAL; | 94 | return -EINVAL; |
92 | 95 | ||
93 | return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); | 96 | err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); |
97 | if (!err) { | ||
98 | rdev->monitor_channel = chan; | ||
99 | rdev->monitor_channel_type = chantype; | ||
100 | } | ||
101 | |||
102 | return err; | ||
103 | } | ||
104 | |||
105 | void | ||
106 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
107 | struct wireless_dev *wdev, | ||
108 | struct ieee80211_channel **chan, | ||
109 | enum cfg80211_chan_mode *chanmode) | ||
110 | { | ||
111 | *chan = NULL; | ||
112 | *chanmode = CHAN_MODE_UNDEFINED; | ||
113 | |||
114 | ASSERT_RDEV_LOCK(rdev); | ||
115 | ASSERT_WDEV_LOCK(wdev); | ||
116 | |||
117 | if (!netif_running(wdev->netdev)) | ||
118 | return; | ||
119 | |||
120 | switch (wdev->iftype) { | ||
121 | case NL80211_IFTYPE_ADHOC: | ||
122 | if (wdev->current_bss) { | ||
123 | *chan = wdev->current_bss->pub.channel; | ||
124 | *chanmode = wdev->ibss_fixed | ||
125 | ? CHAN_MODE_SHARED | ||
126 | : CHAN_MODE_EXCLUSIVE; | ||
127 | return; | ||
128 | } | ||
129 | case NL80211_IFTYPE_STATION: | ||
130 | case NL80211_IFTYPE_P2P_CLIENT: | ||
131 | if (wdev->current_bss) { | ||
132 | *chan = wdev->current_bss->pub.channel; | ||
133 | *chanmode = CHAN_MODE_SHARED; | ||
134 | return; | ||
135 | } | ||
136 | break; | ||
137 | case NL80211_IFTYPE_AP: | ||
138 | case NL80211_IFTYPE_P2P_GO: | ||
139 | case NL80211_IFTYPE_MESH_POINT: | ||
140 | *chan = wdev->channel; | ||
141 | *chanmode = CHAN_MODE_SHARED; | ||
142 | return; | ||
143 | case NL80211_IFTYPE_MONITOR: | ||
144 | case NL80211_IFTYPE_AP_VLAN: | ||
145 | case NL80211_IFTYPE_WDS: | ||
146 | /* these interface types don't really have a channel */ | ||
147 | return; | ||
148 | case NL80211_IFTYPE_UNSPECIFIED: | ||
149 | case NUM_NL80211_IFTYPES: | ||
150 | WARN_ON(1); | ||
151 | } | ||
152 | |||
153 | return; | ||
94 | } | 154 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 907f62c80e28..eb60410ae588 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) | |||
373 | if (WARN_ON(!c->num_different_channels)) | 373 | if (WARN_ON(!c->num_different_channels)) |
374 | return -EINVAL; | 374 | return -EINVAL; |
375 | 375 | ||
376 | /* | ||
377 | * Put a sane limit on maximum number of different | ||
378 | * channels to simplify channel accounting code. | ||
379 | */ | ||
380 | if (WARN_ON(c->num_different_channels > | ||
381 | CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) | ||
382 | return -EINVAL; | ||
383 | |||
376 | if (WARN_ON(!c->n_limits)) | 384 | if (WARN_ON(!c->n_limits)) |
377 | return -EINVAL; | 385 | return -EINVAL; |
378 | 386 | ||
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
421 | int i; | 429 | int i; |
422 | u16 ifmodes = wiphy->interface_modes; | 430 | u16 ifmodes = wiphy->interface_modes; |
423 | 431 | ||
432 | #ifdef CONFIG_PM | ||
424 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | 433 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && |
425 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | 434 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) |
426 | return -EINVAL; | 435 | return -EINVAL; |
436 | #endif | ||
427 | 437 | ||
428 | if (WARN_ON(wiphy->ap_sme_capa && | 438 | if (WARN_ON(wiphy->ap_sme_capa && |
429 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) | 439 | !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) |
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
458 | continue; | 468 | continue; |
459 | 469 | ||
460 | sband->band = band; | 470 | sband->band = band; |
461 | 471 | if (WARN_ON(!sband->n_channels)) | |
462 | if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) | 472 | return -EINVAL; |
473 | /* | ||
474 | * on 60gHz band, there are no legacy rates, so | ||
475 | * n_bitrates is 0 | ||
476 | */ | ||
477 | if (WARN_ON(band != IEEE80211_BAND_60GHZ && | ||
478 | !sband->n_bitrates)) | ||
463 | return -EINVAL; | 479 | return -EINVAL; |
464 | 480 | ||
465 | /* | 481 | /* |
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy) | |||
500 | return -EINVAL; | 516 | return -EINVAL; |
501 | } | 517 | } |
502 | 518 | ||
519 | #ifdef CONFIG_PM | ||
503 | if (rdev->wiphy.wowlan.n_patterns) { | 520 | if (rdev->wiphy.wowlan.n_patterns) { |
504 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | 521 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || |
505 | rdev->wiphy.wowlan.pattern_min_len > | 522 | rdev->wiphy.wowlan.pattern_min_len > |
506 | rdev->wiphy.wowlan.pattern_max_len)) | 523 | rdev->wiphy.wowlan.pattern_max_len)) |
507 | return -EINVAL; | 524 | return -EINVAL; |
508 | } | 525 | } |
526 | #endif | ||
509 | 527 | ||
510 | /* check and set up bitrates */ | 528 | /* check and set up bitrates */ |
511 | ieee80211_set_bitrate_flags(wiphy); | 529 | ieee80211_set_bitrate_flags(wiphy); |
@@ -713,6 +731,61 @@ static struct device_type wiphy_type = { | |||
713 | .name = "wlan", | 731 | .name = "wlan", |
714 | }; | 732 | }; |
715 | 733 | ||
734 | static struct ieee80211_channel * | ||
735 | cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) | ||
736 | { | ||
737 | struct ieee80211_supported_band *sband; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
741 | sband = rdev->wiphy.bands[i]; | ||
742 | if (sband && sband->n_channels > 0) | ||
743 | return &sband->channels[0]; | ||
744 | } | ||
745 | |||
746 | return NULL; | ||
747 | } | ||
748 | |||
749 | static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) | ||
750 | { | ||
751 | struct ieee80211_channel *chan; | ||
752 | |||
753 | chan = cfg80211_get_any_chan(rdev); | ||
754 | if (WARN_ON(!chan)) | ||
755 | return; | ||
756 | |||
757 | mutex_lock(&rdev->devlist_mtx); | ||
758 | WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, | ||
759 | NL80211_CHAN_NO_HT)); | ||
760 | mutex_unlock(&rdev->devlist_mtx); | ||
761 | } | ||
762 | |||
763 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
764 | enum nl80211_iftype iftype, int num) | ||
765 | { | ||
766 | bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); | ||
767 | bool has_monitors_only_new; | ||
768 | |||
769 | ASSERT_RTNL(); | ||
770 | |||
771 | rdev->num_running_ifaces += num; | ||
772 | if (iftype == NL80211_IFTYPE_MONITOR) | ||
773 | rdev->num_running_monitor_ifaces += num; | ||
774 | |||
775 | has_monitors_only_new = cfg80211_has_monitors_only(rdev); | ||
776 | if (has_monitors_only_new != has_monitors_only_old) { | ||
777 | rdev->ops->set_monitor_enabled(&rdev->wiphy, | ||
778 | has_monitors_only_new); | ||
779 | |||
780 | if (!has_monitors_only_new) { | ||
781 | rdev->monitor_channel = NULL; | ||
782 | rdev->monitor_channel_type = NL80211_CHAN_NO_HT; | ||
783 | } else { | ||
784 | cfg80211_init_mon_chan(rdev); | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
716 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | 789 | static int cfg80211_netdev_notifier_call(struct notifier_block *nb, |
717 | unsigned long state, | 790 | unsigned long state, |
718 | void *ndev) | 791 | void *ndev) |
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
806 | case NL80211_IFTYPE_MESH_POINT: | 879 | case NL80211_IFTYPE_MESH_POINT: |
807 | cfg80211_leave_mesh(rdev, dev); | 880 | cfg80211_leave_mesh(rdev, dev); |
808 | break; | 881 | break; |
882 | case NL80211_IFTYPE_AP: | ||
883 | cfg80211_stop_ap(rdev, dev); | ||
884 | break; | ||
809 | default: | 885 | default: |
810 | break; | 886 | break; |
811 | } | 887 | } |
812 | wdev->beacon_interval = 0; | 888 | wdev->beacon_interval = 0; |
813 | break; | 889 | break; |
814 | case NETDEV_DOWN: | 890 | case NETDEV_DOWN: |
891 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | ||
815 | dev_hold(dev); | 892 | dev_hold(dev); |
816 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 893 | queue_work(cfg80211_wq, &wdev->cleanup_work); |
817 | break; | 894 | break; |
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
917 | return notifier_from_errno(-EOPNOTSUPP); | 994 | return notifier_from_errno(-EOPNOTSUPP); |
918 | if (rfkill_blocked(rdev->rfkill)) | 995 | if (rfkill_blocked(rdev->rfkill)) |
919 | return notifier_from_errno(-ERFKILL); | 996 | return notifier_from_errno(-ERFKILL); |
997 | mutex_lock(&rdev->devlist_mtx); | ||
920 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 998 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
999 | mutex_unlock(&rdev->devlist_mtx); | ||
921 | if (ret) | 1000 | if (ret) |
922 | return notifier_from_errno(ret); | 1001 | return notifier_from_errno(ret); |
1002 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | ||
923 | break; | 1003 | break; |
924 | } | 1004 | } |
925 | 1005 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index 609a579255ac..377dc394f48c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/rfkill.h> | 14 | #include <linux/rfkill.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/rtnetlink.h> | ||
16 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
18 | #include "reg.h" | 19 | #include "reg.h" |
@@ -56,6 +57,13 @@ struct cfg80211_registered_device { | |||
56 | 57 | ||
57 | u32 ap_beacons_nlpid; | 58 | u32 ap_beacons_nlpid; |
58 | 59 | ||
60 | /* protected by RTNL only */ | ||
61 | int num_running_ifaces; | ||
62 | int num_running_monitor_ifaces; | ||
63 | |||
64 | struct ieee80211_channel *monitor_channel; | ||
65 | enum nl80211_channel_type monitor_channel_type; | ||
66 | |||
59 | /* BSSes/scanning */ | 67 | /* BSSes/scanning */ |
60 | spinlock_t bss_lock; | 68 | spinlock_t bss_lock; |
61 | struct list_head bss_list; | 69 | struct list_head bss_list; |
@@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
197 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 205 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) |
198 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 206 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
199 | 207 | ||
208 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | ||
209 | { | ||
210 | ASSERT_RTNL(); | ||
211 | |||
212 | return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && | ||
213 | rdev->num_running_ifaces > 0; | ||
214 | } | ||
215 | |||
200 | enum cfg80211_event_type { | 216 | enum cfg80211_event_type { |
201 | EVENT_CONNECT_RESULT, | 217 | EVENT_CONNECT_RESULT, |
202 | EVENT_ROAMED, | 218 | EVENT_ROAMED, |
@@ -241,6 +257,12 @@ struct cfg80211_cached_keys { | |||
241 | int def, defmgmt; | 257 | int def, defmgmt; |
242 | }; | 258 | }; |
243 | 259 | ||
260 | enum cfg80211_chan_mode { | ||
261 | CHAN_MODE_UNDEFINED, | ||
262 | CHAN_MODE_SHARED, | ||
263 | CHAN_MODE_EXCLUSIVE, | ||
264 | }; | ||
265 | |||
244 | 266 | ||
245 | /* free object */ | 267 | /* free object */ |
246 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 268 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
@@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
289 | struct wireless_dev *wdev, int freq, | 311 | struct wireless_dev *wdev, int freq, |
290 | enum nl80211_channel_type channel_type); | 312 | enum nl80211_channel_type channel_type); |
291 | 313 | ||
314 | /* AP */ | ||
315 | int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||
316 | struct net_device *dev); | ||
317 | |||
292 | /* MLME */ | 318 | /* MLME */ |
293 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 319 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
294 | struct net_device *dev, | 320 | struct net_device *dev, |
@@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
404 | u32 *flags, struct vif_params *params); | 430 | u32 *flags, struct vif_params *params); |
405 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | 431 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
406 | 432 | ||
407 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 433 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
408 | struct wireless_dev *wdev, | 434 | struct wireless_dev *wdev, |
409 | enum nl80211_iftype iftype); | 435 | enum nl80211_iftype iftype, |
436 | struct ieee80211_channel *chan, | ||
437 | enum cfg80211_chan_mode chanmode); | ||
438 | |||
439 | static inline int | ||
440 | cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||
441 | struct wireless_dev *wdev, | ||
442 | enum nl80211_iftype iftype) | ||
443 | { | ||
444 | return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, | ||
445 | CHAN_MODE_UNDEFINED); | ||
446 | } | ||
410 | 447 | ||
411 | static inline int | 448 | static inline int |
412 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | 449 | cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, |
@@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, | |||
415 | return cfg80211_can_change_interface(rdev, NULL, iftype); | 452 | return cfg80211_can_change_interface(rdev, NULL, iftype); |
416 | } | 453 | } |
417 | 454 | ||
455 | static inline int | ||
456 | cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, | ||
457 | struct wireless_dev *wdev, | ||
458 | struct ieee80211_channel *chan, | ||
459 | enum cfg80211_chan_mode chanmode) | ||
460 | { | ||
461 | return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
462 | chan, chanmode); | ||
463 | } | ||
464 | |||
465 | void | ||
466 | cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, | ||
467 | struct wireless_dev *wdev, | ||
468 | struct ieee80211_channel **chan, | ||
469 | enum cfg80211_chan_mode *chanmode); | ||
470 | |||
418 | struct ieee80211_channel * | 471 | struct ieee80211_channel * |
419 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | 472 | rdev_freq_to_chan(struct cfg80211_registered_device *rdev, |
420 | int freq, enum nl80211_channel_type channel_type); | 473 | int freq, enum nl80211_channel_type channel_type); |
@@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
428 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 481 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
429 | u32 beacon_int); | 482 | u32 beacon_int); |
430 | 483 | ||
484 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | ||
485 | enum nl80211_iftype iftype, int num); | ||
486 | |||
487 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | ||
488 | |||
431 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 489 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
432 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) | 490 | #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) |
433 | #else | 491 | #else |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89baa3328411..ca5672f6ee2f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
113 | kfree(wdev->connect_keys); | 113 | kfree(wdev->connect_keys); |
114 | wdev->connect_keys = connkeys; | 114 | wdev->connect_keys = connkeys; |
115 | 115 | ||
116 | wdev->ibss_fixed = params->channel_fixed; | ||
116 | #ifdef CONFIG_CFG80211_WEXT | 117 | #ifdef CONFIG_CFG80211_WEXT |
117 | wdev->wext.ibss.channel = params->channel; | 118 | wdev->wext.ibss.channel = params->channel; |
118 | #endif | 119 | #endif |
119 | wdev->sme_state = CFG80211_SME_CONNECTING; | 120 | wdev->sme_state = CFG80211_SME_CONNECTING; |
121 | |||
122 | err = cfg80211_can_use_chan(rdev, wdev, params->channel, | ||
123 | params->channel_fixed | ||
124 | ? CHAN_MODE_SHARED | ||
125 | : CHAN_MODE_EXCLUSIVE); | ||
126 | if (err) { | ||
127 | wdev->connect_keys = NULL; | ||
128 | return err; | ||
129 | } | ||
130 | |||
120 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); | 131 | err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); |
121 | if (err) { | 132 | if (err) { |
122 | wdev->connect_keys = NULL; | 133 | wdev->connect_keys = NULL; |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 3b73b07486cf..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
155 | setup->channel_type)) | 155 | setup->channel_type)) |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | 157 | ||
158 | err = cfg80211_can_use_chan(rdev, wdev, setup->channel, | ||
159 | CHAN_MODE_SHARED); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
158 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); | 163 | err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); |
159 | if (!err) { | 164 | if (!err) { |
160 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 165 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
161 | wdev->mesh_id_len = setup->mesh_id_len; | 166 | wdev->mesh_id_len = setup->mesh_id_len; |
167 | wdev->channel = setup->channel; | ||
162 | } | 168 | } |
163 | 169 | ||
164 | return err; | 170 | return err; |
@@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
172 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 178 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
173 | int err; | 179 | int err; |
174 | 180 | ||
181 | mutex_lock(&rdev->devlist_mtx); | ||
175 | wdev_lock(wdev); | 182 | wdev_lock(wdev); |
176 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 183 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
177 | wdev_unlock(wdev); | 184 | wdev_unlock(wdev); |
185 | mutex_unlock(&rdev->devlist_mtx); | ||
178 | 186 | ||
179 | return err; | 187 | return err; |
180 | } | 188 | } |
@@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
184 | enum nl80211_channel_type channel_type) | 192 | enum nl80211_channel_type channel_type) |
185 | { | 193 | { |
186 | struct ieee80211_channel *channel; | 194 | struct ieee80211_channel *channel; |
195 | int err; | ||
187 | 196 | ||
188 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | 197 | channel = rdev_freq_to_chan(rdev, freq, channel_type); |
189 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | 198 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, |
@@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, | |||
205 | 214 | ||
206 | if (!netif_running(wdev->netdev)) | 215 | if (!netif_running(wdev->netdev)) |
207 | return -ENETDOWN; | 216 | return -ENETDOWN; |
208 | return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | 217 | |
209 | wdev->netdev, | 218 | err = cfg80211_can_use_chan(rdev, wdev, channel, |
210 | channel); | 219 | CHAN_MODE_SHARED); |
220 | if (err) | ||
221 | return err; | ||
222 | |||
223 | err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, | ||
224 | wdev->netdev, | ||
225 | channel); | ||
226 | if (!err) | ||
227 | wdev->channel = channel; | ||
228 | |||
229 | return err; | ||
211 | } | 230 | } |
212 | 231 | ||
213 | if (wdev->mesh_id_len) | 232 | if (wdev->mesh_id_len) |
@@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
249 | return -ENOTCONN; | 268 | return -ENOTCONN; |
250 | 269 | ||
251 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); | 270 | err = rdev->ops->leave_mesh(&rdev->wiphy, dev); |
252 | if (!err) | 271 | if (!err) { |
253 | wdev->mesh_id_len = 0; | 272 | wdev->mesh_id_len = 0; |
273 | wdev->channel = NULL; | ||
274 | } | ||
275 | |||
254 | return err; | 276 | return err; |
255 | } | 277 | } |
256 | 278 | ||
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da4406f11929..d4fece3bb18a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
302 | if (!req.bss) | 302 | if (!req.bss) |
303 | return -ENOENT; | 303 | return -ENOENT; |
304 | 304 | ||
305 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
306 | CHAN_MODE_SHARED); | ||
307 | if (err) | ||
308 | goto out; | ||
309 | |||
305 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | 310 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); |
306 | 311 | ||
312 | out: | ||
307 | cfg80211_put_bss(req.bss); | 313 | cfg80211_put_bss(req.bss); |
308 | return err; | 314 | return err; |
309 | } | 315 | } |
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
317 | { | 323 | { |
318 | int err; | 324 | int err; |
319 | 325 | ||
326 | mutex_lock(&rdev->devlist_mtx); | ||
320 | wdev_lock(dev->ieee80211_ptr); | 327 | wdev_lock(dev->ieee80211_ptr); |
321 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 328 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
322 | ssid, ssid_len, ie, ie_len, | 329 | ssid, ssid_len, ie, ie_len, |
323 | key, key_len, key_idx); | 330 | key, key_len, key_idx); |
324 | wdev_unlock(dev->ieee80211_ptr); | 331 | wdev_unlock(dev->ieee80211_ptr); |
332 | mutex_unlock(&rdev->devlist_mtx); | ||
325 | 333 | ||
326 | return err; | 334 | return err; |
327 | } | 335 | } |
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
397 | return -ENOENT; | 405 | return -ENOENT; |
398 | } | 406 | } |
399 | 407 | ||
408 | err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, | ||
409 | CHAN_MODE_SHARED); | ||
410 | if (err) | ||
411 | goto out; | ||
412 | |||
400 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | 413 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); |
401 | 414 | ||
415 | out: | ||
402 | if (err) { | 416 | if (err) { |
403 | if (was_connected) | 417 | if (was_connected) |
404 | wdev->sme_state = CFG80211_SME_CONNECTED; | 418 | wdev->sme_state = CFG80211_SME_CONNECTED; |
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
421 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 435 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
422 | int err; | 436 | int err; |
423 | 437 | ||
438 | mutex_lock(&rdev->devlist_mtx); | ||
424 | wdev_lock(wdev); | 439 | wdev_lock(wdev); |
425 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 440 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
426 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 441 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
427 | assoc_flags, ht_capa, ht_capa_mask); | 442 | assoc_flags, ht_capa, ht_capa_mask); |
428 | wdev_unlock(wdev); | 443 | wdev_unlock(wdev); |
444 | mutex_unlock(&rdev->devlist_mtx); | ||
429 | 445 | ||
430 | return err; | 446 | return err; |
431 | } | 447 | } |
@@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, | |||
947 | if (WARN_ON(!chan)) | 963 | if (WARN_ON(!chan)) |
948 | goto out; | 964 | goto out; |
949 | 965 | ||
966 | wdev->channel = chan; | ||
950 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); | 967 | nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); |
951 | out: | 968 | out: |
952 | wdev_unlock(wdev); | 969 | wdev_unlock(wdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3b508eaf2d07..0249cea53852 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 921 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
922 | goto nla_put_failure; | 922 | goto nla_put_failure; |
923 | 923 | ||
924 | /* add VHT info */ | ||
925 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
926 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
927 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
928 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
929 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
930 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
931 | goto nla_put_failure; | ||
932 | |||
924 | /* add frequencies */ | 933 | /* add frequencies */ |
925 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 934 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
926 | if (!nl_freqs) | 935 | if (!nl_freqs) |
@@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1112 | nla_nest_end(msg, nl_ifs); | 1121 | nla_nest_end(msg, nl_ifs); |
1113 | } | 1122 | } |
1114 | 1123 | ||
1124 | #ifdef CONFIG_PM | ||
1115 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1125 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1116 | struct nlattr *nl_wowlan; | 1126 | struct nlattr *nl_wowlan; |
1117 | 1127 | ||
@@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1152 | 1162 | ||
1153 | nla_nest_end(msg, nl_wowlan); | 1163 | nla_nest_end(msg, nl_wowlan); |
1154 | } | 1164 | } |
1165 | #endif | ||
1155 | 1166 | ||
1156 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1167 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1157 | dev->wiphy.software_iftypes)) | 1168 | dev->wiphy.software_iftypes)) |
@@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1678 | (cfg80211_rdev_list_generation << 2))) | 1689 | (cfg80211_rdev_list_generation << 2))) |
1679 | goto nla_put_failure; | 1690 | goto nla_put_failure; |
1680 | 1691 | ||
1681 | if (rdev->ops->get_channel) { | 1692 | if (rdev->monitor_channel) { |
1682 | struct ieee80211_channel *chan; | 1693 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1683 | enum nl80211_channel_type channel_type; | 1694 | rdev->monitor_channel->center_freq) || |
1684 | 1695 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | |
1685 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1696 | rdev->monitor_channel_type)) |
1686 | if (chan && | ||
1687 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
1688 | chan->center_freq) || | ||
1689 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
1690 | channel_type))) | ||
1691 | goto nla_put_failure; | 1697 | goto nla_put_failure; |
1692 | } | 1698 | } |
1693 | 1699 | ||
@@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2472 | params.channel_type)) | 2478 | params.channel_type)) |
2473 | return -EINVAL; | 2479 | return -EINVAL; |
2474 | 2480 | ||
2481 | mutex_lock(&rdev->devlist_mtx); | ||
2482 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2483 | CHAN_MODE_SHARED); | ||
2484 | mutex_unlock(&rdev->devlist_mtx); | ||
2485 | |||
2486 | if (err) | ||
2487 | return err; | ||
2488 | |||
2475 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2489 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2476 | if (!err) { | 2490 | if (!err) { |
2477 | wdev->preset_chan = params.channel; | 2491 | wdev->preset_chan = params.channel; |
2478 | wdev->preset_chantype = params.channel_type; | 2492 | wdev->preset_chantype = params.channel_type; |
2479 | wdev->beacon_interval = params.beacon_interval; | 2493 | wdev->beacon_interval = params.beacon_interval; |
2494 | wdev->channel = params.channel; | ||
2480 | } | 2495 | } |
2481 | return err; | 2496 | return err; |
2482 | } | 2497 | } |
@@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2510 | { | 2525 | { |
2511 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2526 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2512 | struct net_device *dev = info->user_ptr[1]; | 2527 | struct net_device *dev = info->user_ptr[1]; |
2513 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2514 | int err; | ||
2515 | 2528 | ||
2516 | if (!rdev->ops->stop_ap) | 2529 | return cfg80211_stop_ap(rdev, dev); |
2517 | return -EOPNOTSUPP; | ||
2518 | |||
2519 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2520 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2521 | return -EOPNOTSUPP; | ||
2522 | |||
2523 | if (!wdev->beacon_interval) | ||
2524 | return -ENOENT; | ||
2525 | |||
2526 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2527 | if (!err) | ||
2528 | wdev->beacon_interval = 0; | ||
2529 | return err; | ||
2530 | } | 2530 | } |
2531 | 2531 | ||
2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2532 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2618 | int attr) | 2618 | int attr) |
2619 | { | 2619 | { |
2620 | struct nlattr *rate; | 2620 | struct nlattr *rate; |
2621 | u16 bitrate; | 2621 | u32 bitrate; |
2622 | u16 bitrate_compat; | ||
2622 | 2623 | ||
2623 | rate = nla_nest_start(msg, attr); | 2624 | rate = nla_nest_start(msg, attr); |
2624 | if (!rate) | 2625 | if (!rate) |
@@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2626 | 2627 | ||
2627 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2628 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2628 | bitrate = cfg80211_calculate_bitrate(info); | 2629 | bitrate = cfg80211_calculate_bitrate(info); |
2630 | /* report 16-bit bitrate only if we can */ | ||
2631 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2629 | if ((bitrate > 0 && | 2632 | if ((bitrate > 0 && |
2630 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2633 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2634 | (bitrate_compat > 0 && | ||
2635 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2631 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2636 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2632 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2637 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2633 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2638 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6276 | return cfg80211_leave_mesh(rdev, dev); | 6281 | return cfg80211_leave_mesh(rdev, dev); |
6277 | } | 6282 | } |
6278 | 6283 | ||
6284 | #ifdef CONFIG_PM | ||
6279 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6285 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6280 | { | 6286 | { |
6281 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6287 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6504 | kfree(new_triggers.patterns); | 6510 | kfree(new_triggers.patterns); |
6505 | return err; | 6511 | return err; |
6506 | } | 6512 | } |
6513 | #endif | ||
6507 | 6514 | ||
6508 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6515 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6509 | { | 6516 | { |
@@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7158 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7165 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
7159 | NL80211_FLAG_NEED_RTNL, | 7166 | NL80211_FLAG_NEED_RTNL, |
7160 | }, | 7167 | }, |
7168 | #ifdef CONFIG_PM | ||
7161 | { | 7169 | { |
7162 | .cmd = NL80211_CMD_GET_WOWLAN, | 7170 | .cmd = NL80211_CMD_GET_WOWLAN, |
7163 | .doit = nl80211_get_wowlan, | 7171 | .doit = nl80211_get_wowlan, |
@@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7174 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7182 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
7175 | NL80211_FLAG_NEED_RTNL, | 7183 | NL80211_FLAG_NEED_RTNL, |
7176 | }, | 7184 | }, |
7185 | #endif | ||
7177 | { | 7186 | { |
7178 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7187 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
7179 | .doit = nl80211_set_rekey_data, | 7188 | .doit = nl80211_set_rekey_data, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704740ee..b2b32229b607 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | |||
129 | 129 | ||
130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 130 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
131 | static const struct ieee80211_regdomain world_regdom = { | 131 | static const struct ieee80211_regdomain world_regdom = { |
132 | .n_reg_rules = 5, | 132 | .n_reg_rules = 6, |
133 | .alpha2 = "00", | 133 | .alpha2 = "00", |
134 | .reg_rules = { | 134 | .reg_rules = { |
135 | /* IEEE 802.11b/g, channels 1..11 */ | 135 | /* IEEE 802.11b/g, channels 1..11 */ |
@@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = { | |||
156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, | 156 | REG_RULE(5745-10, 5825+10, 40, 6, 20, |
157 | NL80211_RRF_PASSIVE_SCAN | | 157 | NL80211_RRF_PASSIVE_SCAN | |
158 | NL80211_RRF_NO_IBSS), | 158 | NL80211_RRF_NO_IBSS), |
159 | |||
160 | /* IEEE 802.11ad (60gHz), channels 1..3 */ | ||
161 | REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), | ||
159 | } | 162 | } |
160 | }; | 163 | }; |
161 | 164 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..e31f1dba79ec 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | |||
35 | { | 35 | { |
36 | /* see 802.11 17.3.8.3.2 and Annex J | 36 | /* see 802.11 17.3.8.3.2 and Annex J |
37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
38 | if (band == IEEE80211_BAND_5GHZ) { | 38 | if (chan <= 0) |
39 | if (chan >= 182 && chan <= 196) | 39 | return 0; /* not supported */ |
40 | return 4000 + chan * 5; | 40 | switch (band) { |
41 | else | 41 | case IEEE80211_BAND_2GHZ: |
42 | return 5000 + chan * 5; | ||
43 | } else { /* IEEE80211_BAND_2GHZ */ | ||
44 | if (chan == 14) | 42 | if (chan == 14) |
45 | return 2484; | 43 | return 2484; |
46 | else if (chan < 14) | 44 | else if (chan < 14) |
47 | return 2407 + chan * 5; | 45 | return 2407 + chan * 5; |
46 | break; | ||
47 | case IEEE80211_BAND_5GHZ: | ||
48 | if (chan >= 182 && chan <= 196) | ||
49 | return 4000 + chan * 5; | ||
48 | else | 50 | else |
49 | return 0; /* not supported */ | 51 | return 5000 + chan * 5; |
52 | break; | ||
53 | case IEEE80211_BAND_60GHZ: | ||
54 | if (chan < 5) | ||
55 | return 56160 + chan * 2160; | ||
56 | break; | ||
57 | default: | ||
58 | ; | ||
50 | } | 59 | } |
60 | return 0; /* not supported */ | ||
51 | } | 61 | } |
52 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 62 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
53 | 63 | ||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) | |||
60 | return (freq - 2407) / 5; | 70 | return (freq - 2407) / 5; |
61 | else if (freq >= 4910 && freq <= 4980) | 71 | else if (freq >= 4910 && freq <= 4980) |
62 | return (freq - 4000) / 5; | 72 | return (freq - 4000) / 5; |
63 | else | 73 | else if (freq <= 45000) /* DMG band lower limit */ |
64 | return (freq - 5000) / 5; | 74 | return (freq - 5000) / 5; |
75 | else if (freq >= 58320 && freq <= 64800) | ||
76 | return (freq - 56160) / 2160; | ||
77 | else | ||
78 | return 0; | ||
65 | } | 79 | } |
66 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 80 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
67 | 81 | ||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | |||
137 | } | 151 | } |
138 | WARN_ON(want != 0 && want != 3 && want != 6); | 152 | WARN_ON(want != 0 && want != 3 && want != 6); |
139 | break; | 153 | break; |
154 | case IEEE80211_BAND_60GHZ: | ||
155 | /* check for mandatory HT MCS 1..4 */ | ||
156 | WARN_ON(!sband->ht_cap.ht_supported); | ||
157 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | ||
158 | break; | ||
140 | case IEEE80211_NUM_BANDS: | 159 | case IEEE80211_NUM_BANDS: |
141 | WARN_ON(1); | 160 | WARN_ON(1); |
142 | break; | 161 | break; |
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
805 | return -EBUSY; | 824 | return -EBUSY; |
806 | 825 | ||
807 | if (ntype != otype && netif_running(dev)) { | 826 | if (ntype != otype && netif_running(dev)) { |
827 | mutex_lock(&rdev->devlist_mtx); | ||
808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 828 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
809 | ntype); | 829 | ntype); |
830 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | if (err) | 831 | if (err) |
811 | return err; | 832 | return err; |
812 | 833 | ||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
814 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 835 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
815 | 836 | ||
816 | switch (otype) { | 837 | switch (otype) { |
838 | case NL80211_IFTYPE_AP: | ||
839 | cfg80211_stop_ap(rdev, dev); | ||
840 | break; | ||
817 | case NL80211_IFTYPE_ADHOC: | 841 | case NL80211_IFTYPE_ADHOC: |
818 | cfg80211_leave_ibss(rdev, dev, false); | 842 | cfg80211_leave_ibss(rdev, dev, false); |
819 | break; | 843 | break; |
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
868 | } | 892 | } |
869 | } | 893 | } |
870 | 894 | ||
895 | if (!err && ntype != otype && netif_running(dev)) { | ||
896 | cfg80211_update_iface_num(rdev, ntype, 1); | ||
897 | cfg80211_update_iface_num(rdev, otype, -1); | ||
898 | } | ||
899 | |||
871 | return err; | 900 | return err; |
872 | } | 901 | } |
873 | 902 | ||
874 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | 903 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
904 | { | ||
905 | static const u32 __mcs2bitrate[] = { | ||
906 | /* control PHY */ | ||
907 | [0] = 275, | ||
908 | /* SC PHY */ | ||
909 | [1] = 3850, | ||
910 | [2] = 7700, | ||
911 | [3] = 9625, | ||
912 | [4] = 11550, | ||
913 | [5] = 12512, /* 1251.25 mbps */ | ||
914 | [6] = 15400, | ||
915 | [7] = 19250, | ||
916 | [8] = 23100, | ||
917 | [9] = 25025, | ||
918 | [10] = 30800, | ||
919 | [11] = 38500, | ||
920 | [12] = 46200, | ||
921 | /* OFDM PHY */ | ||
922 | [13] = 6930, | ||
923 | [14] = 8662, /* 866.25 mbps */ | ||
924 | [15] = 13860, | ||
925 | [16] = 17325, | ||
926 | [17] = 20790, | ||
927 | [18] = 27720, | ||
928 | [19] = 34650, | ||
929 | [20] = 41580, | ||
930 | [21] = 45045, | ||
931 | [22] = 51975, | ||
932 | [23] = 62370, | ||
933 | [24] = 67568, /* 6756.75 mbps */ | ||
934 | /* LP-SC PHY */ | ||
935 | [25] = 6260, | ||
936 | [26] = 8340, | ||
937 | [27] = 11120, | ||
938 | [28] = 12510, | ||
939 | [29] = 16680, | ||
940 | [30] = 22240, | ||
941 | [31] = 25030, | ||
942 | }; | ||
943 | |||
944 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | ||
945 | return 0; | ||
946 | |||
947 | return __mcs2bitrate[rate->mcs]; | ||
948 | } | ||
949 | |||
950 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
875 | { | 951 | { |
876 | int modulation, streams, bitrate; | 952 | int modulation, streams, bitrate; |
877 | 953 | ||
878 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 954 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
879 | return rate->legacy; | 955 | return rate->legacy; |
956 | if (rate->flags & RATE_INFO_FLAGS_60G) | ||
957 | return cfg80211_calculate_bitrate_60g(rate); | ||
880 | 958 | ||
881 | /* the formula below does only work for MCS values smaller than 32 */ | 959 | /* the formula below does only work for MCS values smaller than 32 */ |
882 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 960 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -930,27 +1008,48 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
930 | return res; | 1008 | return res; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 1011 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
934 | struct wireless_dev *wdev, | 1012 | struct wireless_dev *wdev, |
935 | enum nl80211_iftype iftype) | 1013 | enum nl80211_iftype iftype, |
1014 | struct ieee80211_channel *chan, | ||
1015 | enum cfg80211_chan_mode chanmode) | ||
936 | { | 1016 | { |
937 | struct wireless_dev *wdev_iter; | 1017 | struct wireless_dev *wdev_iter; |
938 | u32 used_iftypes = BIT(iftype); | 1018 | u32 used_iftypes = BIT(iftype); |
939 | int num[NUM_NL80211_IFTYPES]; | 1019 | int num[NUM_NL80211_IFTYPES]; |
1020 | struct ieee80211_channel | ||
1021 | *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; | ||
1022 | struct ieee80211_channel *ch; | ||
1023 | enum cfg80211_chan_mode chmode; | ||
1024 | int num_different_channels = 0; | ||
940 | int total = 1; | 1025 | int total = 1; |
941 | int i, j; | 1026 | int i, j; |
942 | 1027 | ||
943 | ASSERT_RTNL(); | 1028 | ASSERT_RTNL(); |
1029 | lockdep_assert_held(&rdev->devlist_mtx); | ||
944 | 1030 | ||
945 | /* Always allow software iftypes */ | 1031 | /* Always allow software iftypes */ |
946 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1032 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
947 | return 0; | 1033 | return 0; |
948 | 1034 | ||
949 | memset(num, 0, sizeof(num)); | 1035 | memset(num, 0, sizeof(num)); |
1036 | memset(used_channels, 0, sizeof(used_channels)); | ||
950 | 1037 | ||
951 | num[iftype] = 1; | 1038 | num[iftype] = 1; |
952 | 1039 | ||
953 | mutex_lock(&rdev->devlist_mtx); | 1040 | switch (chanmode) { |
1041 | case CHAN_MODE_UNDEFINED: | ||
1042 | break; | ||
1043 | case CHAN_MODE_SHARED: | ||
1044 | WARN_ON(!chan); | ||
1045 | used_channels[0] = chan; | ||
1046 | num_different_channels++; | ||
1047 | break; | ||
1048 | case CHAN_MODE_EXCLUSIVE: | ||
1049 | num_different_channels++; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1053 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { |
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
@@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
960 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1059 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
961 | continue; | 1060 | continue; |
962 | 1061 | ||
1062 | cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); | ||
1063 | |||
1064 | switch (chmode) { | ||
1065 | case CHAN_MODE_UNDEFINED: | ||
1066 | break; | ||
1067 | case CHAN_MODE_SHARED: | ||
1068 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1069 | if (!used_channels[i] || used_channels[i] == ch) | ||
1070 | break; | ||
1071 | |||
1072 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1073 | return -EBUSY; | ||
1074 | |||
1075 | if (used_channels[i] == NULL) { | ||
1076 | used_channels[i] = ch; | ||
1077 | num_different_channels++; | ||
1078 | } | ||
1079 | break; | ||
1080 | case CHAN_MODE_EXCLUSIVE: | ||
1081 | num_different_channels++; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
963 | num[wdev_iter->iftype]++; | 1085 | num[wdev_iter->iftype]++; |
964 | total++; | 1086 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1087 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1088 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1089 | ||
969 | if (total == 1) | 1090 | if (total == 1) |
970 | return 0; | 1091 | return 0; |
@@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1097 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1098 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1099 | ||
1100 | if (total > c->max_interfaces) | ||
1101 | continue; | ||
1102 | if (num_different_channels > c->num_different_channels) | ||
1103 | continue; | ||
1104 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1105 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1106 | GFP_KERNEL); |
981 | if (!limits) | 1107 | if (!limits) |
982 | return -ENOMEM; | 1108 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1109 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1110 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1111 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bc879833b21f..7df42f541873 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
827 | { | 827 | { |
828 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 828 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 829 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
830 | struct ieee80211_channel *chan; | ||
831 | enum nl80211_channel_type channel_type; | ||
832 | 830 | ||
833 | switch (wdev->iftype) { | 831 | switch (wdev->iftype) { |
834 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
@@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, | |||
836 | case NL80211_IFTYPE_ADHOC: | 834 | case NL80211_IFTYPE_ADHOC: |
837 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | 835 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); |
838 | case NL80211_IFTYPE_MONITOR: | 836 | case NL80211_IFTYPE_MONITOR: |
839 | if (!rdev->ops->get_channel) | 837 | if (!rdev->monitor_channel) |
840 | return -EINVAL; | 838 | return -EINVAL; |
841 | 839 | ||
842 | chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); | 840 | freq->m = rdev->monitor_channel->center_freq; |
843 | if (!chan) | ||
844 | return -EINVAL; | ||
845 | freq->m = chan->center_freq; | ||
846 | freq->e = 6; | 841 | freq->e = 6; |
847 | return 0; | 842 | return 0; |
848 | default: | 843 | default: |