Commit | Line | Data |
---|---|---|
5449c685 FB |
1 | /* |
2 | * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
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 along | |
16 | * with this program; if not, write to the Free Software Foundation, Inc., | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 | * | |
19 | * File: device_main.c | |
20 | * | |
21 | * Purpose: driver entry for initial, open, close, tx and rx. | |
22 | * | |
23 | * Author: Lyndon Chen | |
24 | * | |
25 | * Date: Jan 8, 2003 | |
26 | * | |
27 | * Functions: | |
28 | * | |
013a468c CC |
29 | * vt6655_probe - module initial (insmod) driver entry |
30 | * vt6655_remove - module remove entry | |
5449c685 | 31 | * device_free_info - device structure resource free function |
5449c685 | 32 | * device_print_info - print out resource |
5449c685 | 33 | * device_rx_srv - rx service function |
5449c685 | 34 | * device_alloc_rx_buf - rx buffer pre-allocated function |
5449c685 | 35 | * device_free_tx_buf - free tx buffer function |
5449c685 FB |
36 | * device_init_rd0_ring- initial rd dma0 ring |
37 | * device_init_rd1_ring- initial rd dma1 ring | |
38 | * device_init_td0_ring- initial tx dma0 ring buffer | |
39 | * device_init_td1_ring- initial tx dma1 ring buffer | |
40 | * device_init_registers- initial MAC & BBP & RF internal registers. | |
41 | * device_init_rings- initial tx/rx ring buffer | |
5449c685 FB |
42 | * device_free_rings- free all allocated ring buffer |
43 | * device_tx_srv- tx interrupt service function | |
44 | * | |
45 | * Revision History: | |
46 | */ | |
47 | #undef __NO_VERSION__ | |
48 | ||
f805442e | 49 | #include <linux/file.h> |
5449c685 | 50 | #include "device.h" |
5449c685 | 51 | #include "card.h" |
79566eb2 | 52 | #include "channel.h" |
5449c685 | 53 | #include "baseband.h" |
5449c685 | 54 | #include "mac.h" |
5449c685 | 55 | #include "power.h" |
5449c685 | 56 | #include "rxtx.h" |
5449c685 | 57 | #include "dpc.h" |
5449c685 | 58 | #include "rf.h" |
5449c685 FB |
59 | #include <linux/delay.h> |
60 | #include <linux/kthread.h> | |
5a0e3ad6 | 61 | #include <linux/slab.h> |
5449c685 | 62 | |
5449c685 | 63 | /*--------------------- Static Definitions -------------------------*/ |
bb72dd53 AS |
64 | /* |
65 | * Define module options | |
66 | */ | |
5449c685 FB |
67 | MODULE_AUTHOR("VIA Networking Technologies, Inc., <lyndonchen@vntek.com.tw>"); |
68 | MODULE_LICENSE("GPL"); | |
69 | MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver"); | |
5449c685 | 70 | |
915006cd | 71 | #define DEVICE_PARAM(N, D) |
5449c685 FB |
72 | |
73 | #define RX_DESC_MIN0 16 | |
74 | #define RX_DESC_MAX0 128 | |
75 | #define RX_DESC_DEF0 32 | |
915006cd | 76 | DEVICE_PARAM(RxDescriptors0, "Number of receive descriptors0"); |
5449c685 FB |
77 | |
78 | #define RX_DESC_MIN1 16 | |
79 | #define RX_DESC_MAX1 128 | |
80 | #define RX_DESC_DEF1 32 | |
915006cd | 81 | DEVICE_PARAM(RxDescriptors1, "Number of receive descriptors1"); |
5449c685 FB |
82 | |
83 | #define TX_DESC_MIN0 16 | |
84 | #define TX_DESC_MAX0 128 | |
85 | #define TX_DESC_DEF0 32 | |
915006cd | 86 | DEVICE_PARAM(TxDescriptors0, "Number of transmit descriptors0"); |
5449c685 FB |
87 | |
88 | #define TX_DESC_MIN1 16 | |
89 | #define TX_DESC_MAX1 128 | |
90 | #define TX_DESC_DEF1 64 | |
915006cd | 91 | DEVICE_PARAM(TxDescriptors1, "Number of transmit descriptors1"); |
5449c685 | 92 | |
5449c685 FB |
93 | #define INT_WORKS_DEF 20 |
94 | #define INT_WORKS_MIN 10 | |
95 | #define INT_WORKS_MAX 64 | |
96 | ||
915006cd | 97 | DEVICE_PARAM(int_works, "Number of packets per interrupt services"); |
5449c685 | 98 | |
5449c685 FB |
99 | #define RTS_THRESH_DEF 2347 |
100 | ||
5449c685 FB |
101 | #define FRAG_THRESH_DEF 2346 |
102 | ||
5449c685 FB |
103 | #define SHORT_RETRY_MIN 0 |
104 | #define SHORT_RETRY_MAX 31 | |
105 | #define SHORT_RETRY_DEF 8 | |
106 | ||
5449c685 FB |
107 | DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits"); |
108 | ||
109 | #define LONG_RETRY_MIN 0 | |
110 | #define LONG_RETRY_MAX 15 | |
111 | #define LONG_RETRY_DEF 4 | |
112 | ||
5449c685 FB |
113 | DEVICE_PARAM(LongRetryLimit, "long frame retry limits"); |
114 | ||
5449c685 | 115 | /* BasebandType[] baseband type selected |
9877f9de AJ |
116 | * 0: indicate 802.11a type |
117 | * 1: indicate 802.11b type | |
118 | * 2: indicate 802.11g type | |
119 | */ | |
5449c685 FB |
120 | #define BBP_TYPE_MIN 0 |
121 | #define BBP_TYPE_MAX 2 | |
122 | #define BBP_TYPE_DEF 2 | |
123 | ||
124 | DEVICE_PARAM(BasebandType, "baseband type"); | |
125 | ||
bb72dd53 AS |
126 | /* |
127 | * Static vars definitions | |
128 | */ | |
9e4c5c28 | 129 | static const struct pci_device_id vt6655_pci_id_table[] = { |
319755a7 | 130 | { PCI_VDEVICE(VIA, 0x3253) }, |
db6cb903 | 131 | { 0, } |
5449c685 | 132 | }; |
5449c685 FB |
133 | |
134 | /*--------------------- Static Functions --------------------------*/ | |
135 | ||
013a468c | 136 | static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent); |
78e0e853 MP |
137 | static void device_free_info(struct vnt_private *priv); |
138 | static void device_print_info(struct vnt_private *priv); | |
5449c685 | 139 | |
78e0e853 MP |
140 | static void device_init_rd0_ring(struct vnt_private *priv); |
141 | static void device_init_rd1_ring(struct vnt_private *priv); | |
142 | static void device_init_td0_ring(struct vnt_private *priv); | |
143 | static void device_init_td1_ring(struct vnt_private *priv); | |
5449c685 | 144 | |
0924a89b MP |
145 | static int device_rx_srv(struct vnt_private *priv, unsigned int idx); |
146 | static int device_tx_srv(struct vnt_private *priv, unsigned int idx); | |
9cb693f6 | 147 | static bool device_alloc_rx_buf(struct vnt_private *, struct vnt_rx_desc *); |
78e0e853 | 148 | static void device_init_registers(struct vnt_private *priv); |
e2357271 | 149 | static void device_free_tx_buf(struct vnt_private *, struct vnt_tx_desc *); |
78e0e853 MP |
150 | static void device_free_td0_ring(struct vnt_private *priv); |
151 | static void device_free_td1_ring(struct vnt_private *priv); | |
152 | static void device_free_rd0_ring(struct vnt_private *priv); | |
153 | static void device_free_rd1_ring(struct vnt_private *priv); | |
154 | static void device_free_rings(struct vnt_private *priv); | |
5449c685 | 155 | |
5449c685 FB |
156 | /*--------------------- Export Variables --------------------------*/ |
157 | ||
158 | /*--------------------- Export Functions --------------------------*/ | |
159 | ||
f4e1b7c8 | 160 | static void vt6655_remove(struct pci_dev *pcid) |
5449c685 | 161 | { |
78e0e853 | 162 | struct vnt_private *priv = pci_get_drvdata(pcid); |
5449c685 | 163 | |
78e0e853 | 164 | if (priv == NULL) |
3ac9e0fd | 165 | return; |
78e0e853 | 166 | device_free_info(priv); |
5449c685 FB |
167 | } |
168 | ||
78e0e853 | 169 | static void device_get_options(struct vnt_private *priv) |
bf76ebd9 | 170 | { |
bc667b99 | 171 | struct vnt_options *opts = &priv->opts; |
bf76ebd9 | 172 | |
bc667b99 MP |
173 | opts->rx_descs0 = RX_DESC_DEF0; |
174 | opts->rx_descs1 = RX_DESC_DEF1; | |
175 | opts->tx_descs[0] = TX_DESC_DEF0; | |
176 | opts->tx_descs[1] = TX_DESC_DEF1; | |
177 | opts->int_works = INT_WORKS_DEF; | |
bf76ebd9 | 178 | |
bc667b99 MP |
179 | opts->short_retry = SHORT_RETRY_DEF; |
180 | opts->long_retry = LONG_RETRY_DEF; | |
181 | opts->bbp_type = BBP_TYPE_DEF; | |
5449c685 FB |
182 | } |
183 | ||
184 | static void | |
78e0e853 | 185 | device_set_options(struct vnt_private *priv) |
3f8597f4 | 186 | { |
bc667b99 MP |
187 | priv->byShortRetryLimit = priv->opts.short_retry; |
188 | priv->byLongRetryLimit = priv->opts.long_retry; | |
189 | priv->byBBType = priv->opts.bbp_type; | |
78e0e853 MP |
190 | priv->byPacketType = priv->byBBType; |
191 | priv->byAutoFBCtrl = AUTO_FB_0; | |
192 | priv->bUpdateBBVGA = true; | |
193 | priv->byPreambleType = 0; | |
194 | ||
195 | pr_debug(" byShortRetryLimit= %d\n", (int)priv->byShortRetryLimit); | |
196 | pr_debug(" byLongRetryLimit= %d\n", (int)priv->byLongRetryLimit); | |
197 | pr_debug(" byPreambleType= %d\n", (int)priv->byPreambleType); | |
198 | pr_debug(" byShortPreamble= %d\n", (int)priv->byShortPreamble); | |
199 | pr_debug(" byBBType= %d\n", (int)priv->byBBType); | |
5449c685 FB |
200 | } |
201 | ||
bb72dd53 AS |
202 | /* |
203 | * Initialisation of MAC & BBP registers | |
204 | */ | |
5449c685 | 205 | |
78e0e853 | 206 | static void device_init_registers(struct vnt_private *priv) |
5449c685 | 207 | { |
10d6f1b7 | 208 | unsigned long flags; |
915006cd JP |
209 | unsigned int ii; |
210 | unsigned char byValue; | |
915006cd JP |
211 | unsigned char byCCKPwrdBm = 0; |
212 | unsigned char byOFDMPwrdBm = 0; | |
6b711271 | 213 | |
f9f853af | 214 | MACbShutdown(priv); |
78e0e853 | 215 | BBvSoftwareReset(priv); |
915006cd | 216 | |
9f34de35 | 217 | /* Do MACbSoftwareReset in MACvInitialize */ |
f9f853af | 218 | MACbSoftwareReset(priv); |
915006cd | 219 | |
78e0e853 | 220 | priv->bAES = false; |
915006cd | 221 | |
9f34de35 | 222 | /* Only used in 11g type, sync with ERP IE */ |
78e0e853 | 223 | priv->bProtectMode = false; |
915006cd | 224 | |
78e0e853 MP |
225 | priv->bNonERPPresent = false; |
226 | priv->bBarkerPreambleMd = false; | |
227 | priv->wCurrentRate = RATE_1M; | |
228 | priv->byTopOFDMBasicRate = RATE_24M; | |
229 | priv->byTopCCKBasicRate = RATE_1M; | |
915006cd | 230 | |
9f34de35 | 231 | /* init MAC */ |
f9f853af | 232 | MACvInitialize(priv); |
9f34de35 MP |
233 | |
234 | /* Get Local ID */ | |
78e0e853 | 235 | VNSvInPortB(priv->PortOffset + MAC_REG_LOCALID, &priv->byLocalID); |
915006cd | 236 | |
78e0e853 | 237 | spin_lock_irqsave(&priv->lock, flags); |
915006cd | 238 | |
78e0e853 | 239 | SROMvReadAllContents(priv->PortOffset, priv->abyEEPROM); |
915006cd | 240 | |
78e0e853 | 241 | spin_unlock_irqrestore(&priv->lock, flags); |
915006cd | 242 | |
9f34de35 | 243 | /* Get Channel range */ |
78e0e853 MP |
244 | priv->byMinChannel = 1; |
245 | priv->byMaxChannel = CB_MAX_CHANNEL; | |
915006cd | 246 | |
9f34de35 | 247 | /* Get Antena */ |
78e0e853 | 248 | byValue = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_ANTENNA); |
9f34de35 | 249 | if (byValue & EEP_ANTINV) |
78e0e853 | 250 | priv->bTxRxAntInv = true; |
9f34de35 | 251 | else |
78e0e853 | 252 | priv->bTxRxAntInv = false; |
9f34de35 MP |
253 | |
254 | byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); | |
255 | /* if not set default is All */ | |
256 | if (byValue == 0) | |
257 | byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); | |
258 | ||
9f34de35 | 259 | if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { |
78e0e853 MP |
260 | priv->byAntennaCount = 2; |
261 | priv->byTxAntennaMode = ANT_B; | |
262 | priv->dwTxAntennaSel = 1; | |
263 | priv->dwRxAntennaSel = 1; | |
9f34de35 | 264 | |
78e0e853 MP |
265 | if (priv->bTxRxAntInv) |
266 | priv->byRxAntennaMode = ANT_A; | |
915006cd | 267 | else |
78e0e853 | 268 | priv->byRxAntennaMode = ANT_B; |
9f34de35 | 269 | } else { |
78e0e853 MP |
270 | priv->byAntennaCount = 1; |
271 | priv->dwTxAntennaSel = 0; | |
272 | priv->dwRxAntennaSel = 0; | |
915006cd | 273 | |
9f34de35 | 274 | if (byValue & EEP_ANTENNA_AUX) { |
78e0e853 | 275 | priv->byTxAntennaMode = ANT_A; |
915006cd | 276 | |
78e0e853 MP |
277 | if (priv->bTxRxAntInv) |
278 | priv->byRxAntennaMode = ANT_B; | |
9f34de35 | 279 | else |
78e0e853 | 280 | priv->byRxAntennaMode = ANT_A; |
9f34de35 | 281 | } else { |
78e0e853 | 282 | priv->byTxAntennaMode = ANT_B; |
9f34de35 | 283 | |
78e0e853 MP |
284 | if (priv->bTxRxAntInv) |
285 | priv->byRxAntennaMode = ANT_A; | |
915006cd | 286 | else |
78e0e853 | 287 | priv->byRxAntennaMode = ANT_B; |
915006cd | 288 | } |
9f34de35 | 289 | } |
5449c685 | 290 | |
918185f6 | 291 | /* Set initial antenna mode */ |
78e0e853 MP |
292 | BBvSetTxAntennaMode(priv, priv->byTxAntennaMode); |
293 | BBvSetRxAntennaMode(priv, priv->byRxAntennaMode); | |
918185f6 | 294 | |
9f34de35 | 295 | /* zonetype initial */ |
78e0e853 | 296 | priv->byOriginalZonetype = priv->abyEEPROM[EEP_OFS_ZONETYPE]; |
915006cd | 297 | |
78e0e853 MP |
298 | if (!priv->bZoneRegExist) |
299 | priv->byZoneType = priv->abyEEPROM[EEP_OFS_ZONETYPE]; | |
bc5cf656 | 300 | |
78e0e853 | 301 | pr_debug("priv->byZoneType = %x\n", priv->byZoneType); |
915006cd | 302 | |
9f34de35 | 303 | /* Init RF module */ |
78e0e853 | 304 | RFbInit(priv); |
915006cd | 305 | |
9f34de35 | 306 | /* Get Desire Power Value */ |
78e0e853 MP |
307 | priv->byCurPwr = 0xFF; |
308 | priv->byCCKPwr = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_PWR_CCK); | |
309 | priv->byOFDMPwrG = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_PWR_OFDMG); | |
f2046f93 | 310 | |
9f34de35 MP |
311 | /* Load power Table */ |
312 | for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) { | |
78e0e853 MP |
313 | priv->abyCCKPwrTbl[ii + 1] = |
314 | SROMbyReadEmbedded(priv->PortOffset, | |
9f34de35 | 315 | (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL)); |
78e0e853 MP |
316 | if (priv->abyCCKPwrTbl[ii + 1] == 0) |
317 | priv->abyCCKPwrTbl[ii+1] = priv->byCCKPwr; | |
5449c685 | 318 | |
78e0e853 MP |
319 | priv->abyOFDMPwrTbl[ii + 1] = |
320 | SROMbyReadEmbedded(priv->PortOffset, | |
9f34de35 | 321 | (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL)); |
78e0e853 MP |
322 | if (priv->abyOFDMPwrTbl[ii + 1] == 0) |
323 | priv->abyOFDMPwrTbl[ii + 1] = priv->byOFDMPwrG; | |
bc5cf656 | 324 | |
78e0e853 MP |
325 | priv->abyCCKDefaultPwr[ii + 1] = byCCKPwrdBm; |
326 | priv->abyOFDMDefaultPwr[ii + 1] = byOFDMPwrdBm; | |
9f34de35 | 327 | } |
bc5cf656 | 328 | |
9f34de35 | 329 | /* recover 12,13 ,14channel for EUROPE by 11 channel */ |
f4cf678f | 330 | for (ii = 11; ii < 14; ii++) { |
78e0e853 MP |
331 | priv->abyCCKPwrTbl[ii] = priv->abyCCKPwrTbl[10]; |
332 | priv->abyOFDMPwrTbl[ii] = priv->abyOFDMPwrTbl[10]; | |
9f34de35 | 333 | } |
5449c685 | 334 | |
9f34de35 MP |
335 | /* Load OFDM A Power Table */ |
336 | for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { | |
78e0e853 MP |
337 | priv->abyOFDMPwrTbl[ii + CB_MAX_CHANNEL_24G + 1] = |
338 | SROMbyReadEmbedded(priv->PortOffset, | |
9f34de35 | 339 | (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL)); |
5449c685 | 340 | |
78e0e853 MP |
341 | priv->abyOFDMDefaultPwr[ii + CB_MAX_CHANNEL_24G + 1] = |
342 | SROMbyReadEmbedded(priv->PortOffset, | |
9f34de35 MP |
343 | (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm)); |
344 | } | |
5449c685 | 345 | |
78e0e853 MP |
346 | if (priv->byLocalID > REV_ID_VT3253_B1) { |
347 | MACvSelectPage1(priv->PortOffset); | |
5449c685 | 348 | |
78e0e853 | 349 | VNSvOutPortB(priv->PortOffset + MAC_REG_MSRCTL + 1, |
9f34de35 | 350 | (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN)); |
5449c685 | 351 | |
78e0e853 | 352 | MACvSelectPage0(priv->PortOffset); |
9f34de35 | 353 | } |
5449c685 | 354 | |
9f34de35 | 355 | /* use relative tx timeout and 802.11i D4 */ |
78e0e853 | 356 | MACvWordRegBitsOn(priv->PortOffset, |
9f34de35 | 357 | MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); |
5449c685 | 358 | |
9f34de35 | 359 | /* set performance parameter by registry */ |
f9f853af MP |
360 | MACvSetShortRetryLimit(priv, priv->byShortRetryLimit); |
361 | MACvSetLongRetryLimit(priv, priv->byLongRetryLimit); | |
5449c685 | 362 | |
9f34de35 | 363 | /* reset TSF counter */ |
78e0e853 | 364 | VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); |
9f34de35 | 365 | /* enable TSF counter */ |
78e0e853 | 366 | VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); |
5449c685 | 367 | |
9f34de35 | 368 | /* initialize BBP registers */ |
78e0e853 | 369 | BBbVT3253Init(priv); |
5449c685 | 370 | |
78e0e853 MP |
371 | if (priv->bUpdateBBVGA) { |
372 | priv->byBBVGACurrent = priv->abyBBVGA[0]; | |
373 | priv->byBBVGANew = priv->byBBVGACurrent; | |
374 | BBvSetVGAGainOffset(priv, priv->abyBBVGA[0]); | |
9f34de35 | 375 | } |
5449c685 | 376 | |
78e0e853 MP |
377 | BBvSetRxAntennaMode(priv, priv->byRxAntennaMode); |
378 | BBvSetTxAntennaMode(priv, priv->byTxAntennaMode); | |
5449c685 | 379 | |
9f34de35 MP |
380 | /* Set BB and packet type at the same time. */ |
381 | /* Set Short Slot Time, xIFS, and RSPINF. */ | |
78e0e853 | 382 | priv->wCurrentRate = RATE_54M; |
bc5cf656 | 383 | |
78e0e853 | 384 | priv->bRadioOff = false; |
5449c685 | 385 | |
78e0e853 | 386 | priv->byRadioCtl = SROMbyReadEmbedded(priv->PortOffset, |
9f34de35 | 387 | EEP_OFS_RADIOCTL); |
78e0e853 | 388 | priv->bHWRadioOff = false; |
5449c685 | 389 | |
78e0e853 | 390 | if (priv->byRadioCtl & EEP_RADIOCTL_ENABLE) { |
9f34de35 | 391 | /* Get GPIO */ |
78e0e853 | 392 | MACvGPIOIn(priv->PortOffset, &priv->byGPIO); |
9f34de35 | 393 | |
78e0e853 MP |
394 | if (((priv->byGPIO & GPIO0_DATA) && |
395 | !(priv->byRadioCtl & EEP_RADIOCTL_INV)) || | |
396 | (!(priv->byGPIO & GPIO0_DATA) && | |
397 | (priv->byRadioCtl & EEP_RADIOCTL_INV))) | |
398 | priv->bHWRadioOff = true; | |
915006cd | 399 | } |
9f34de35 | 400 | |
78e0e853 MP |
401 | if (priv->bHWRadioOff || priv->bRadioControlOff) |
402 | CARDbRadioPowerOff(priv); | |
5449c685 | 403 | |
3500a1da | 404 | /* get Permanent network address */ |
78e0e853 MP |
405 | SROMvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr); |
406 | pr_debug("Network address = %pM\n", priv->abyCurrentNetAddr); | |
915006cd | 407 | |
3500a1da | 408 | /* reset Tx pointer */ |
78e0e853 | 409 | CARDvSafeResetRx(priv); |
3500a1da | 410 | /* reset Rx pointer */ |
78e0e853 | 411 | CARDvSafeResetTx(priv); |
5449c685 | 412 | |
78e0e853 MP |
413 | if (priv->byLocalID <= REV_ID_VT3253_A1) |
414 | MACvRegBitsOn(priv->PortOffset, MAC_REG_RCR, RCR_WPAERR); | |
5449c685 | 415 | |
3500a1da | 416 | /* Turn On Rx DMA */ |
78e0e853 MP |
417 | MACvReceive0(priv->PortOffset); |
418 | MACvReceive1(priv->PortOffset); | |
5449c685 | 419 | |
3500a1da | 420 | /* start the adapter */ |
78e0e853 | 421 | MACvStart(priv->PortOffset); |
5449c685 FB |
422 | } |
423 | ||
78e0e853 | 424 | static void device_print_info(struct vnt_private *priv) |
5449c685 | 425 | { |
78e0e853 MP |
426 | dev_info(&priv->pcid->dev, "MAC=%pM IO=0x%lx Mem=0x%lx IRQ=%d\n", |
427 | priv->abyCurrentNetAddr, (unsigned long)priv->ioaddr, | |
428 | (unsigned long)priv->PortOffset, priv->pcid->irq); | |
5449c685 FB |
429 | } |
430 | ||
78e0e853 | 431 | static void device_free_info(struct vnt_private *priv) |
84b50762 | 432 | { |
78e0e853 | 433 | if (!priv) |
14e53006 | 434 | return; |
5449c685 | 435 | |
78e0e853 MP |
436 | if (priv->mac_hw) |
437 | ieee80211_unregister_hw(priv->hw); | |
5449c685 | 438 | |
78e0e853 MP |
439 | if (priv->PortOffset) |
440 | iounmap(priv->PortOffset); | |
5449c685 | 441 | |
78e0e853 MP |
442 | if (priv->pcid) |
443 | pci_release_regions(priv->pcid); | |
14e53006 | 444 | |
78e0e853 MP |
445 | if (priv->hw) |
446 | ieee80211_free_hw(priv->hw); | |
5449c685 | 447 | } |
5449c685 | 448 | |
78e0e853 | 449 | static bool device_init_rings(struct vnt_private *priv) |
84b50762 | 450 | { |
915006cd | 451 | void *vir_pool; |
5449c685 | 452 | |
915006cd | 453 | /*allocate all RD/TD rings a single pool*/ |
78e0e853 | 454 | vir_pool = dma_zalloc_coherent(&priv->pcid->dev, |
bc667b99 MP |
455 | priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + |
456 | priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + | |
457 | priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + | |
458 | priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), | |
78e0e853 | 459 | &priv->pool_dma, GFP_ATOMIC); |
915006cd | 460 | if (vir_pool == NULL) { |
78e0e853 | 461 | dev_err(&priv->pcid->dev, "allocate desc dma memory failed\n"); |
915006cd JP |
462 | return false; |
463 | } | |
5449c685 | 464 | |
78e0e853 MP |
465 | priv->aRD0Ring = vir_pool; |
466 | priv->aRD1Ring = vir_pool + | |
bc667b99 | 467 | priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc); |
78e0e853 MP |
468 | |
469 | priv->rd0_pool_dma = priv->pool_dma; | |
470 | priv->rd1_pool_dma = priv->rd0_pool_dma + | |
bc667b99 | 471 | priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc); |
78e0e853 MP |
472 | |
473 | priv->tx0_bufs = dma_zalloc_coherent(&priv->pcid->dev, | |
bc667b99 MP |
474 | priv->opts.tx_descs[0] * PKT_BUF_SZ + |
475 | priv->opts.tx_descs[1] * PKT_BUF_SZ + | |
78e0e853 MP |
476 | CB_BEACON_BUF_SIZE + |
477 | CB_MAX_BUF_SIZE, | |
478 | &priv->tx_bufs_dma0, | |
479 | GFP_ATOMIC); | |
480 | if (priv->tx0_bufs == NULL) { | |
481 | dev_err(&priv->pcid->dev, "allocate buf dma memory failed\n"); | |
482 | ||
483 | dma_free_coherent(&priv->pcid->dev, | |
bc667b99 MP |
484 | priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + |
485 | priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + | |
486 | priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + | |
487 | priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), | |
78e0e853 | 488 | vir_pool, priv->pool_dma); |
915006cd JP |
489 | return false; |
490 | } | |
5449c685 | 491 | |
78e0e853 | 492 | priv->td0_pool_dma = priv->rd1_pool_dma + |
bc667b99 | 493 | priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc); |
5449c685 | 494 | |
78e0e853 | 495 | priv->td1_pool_dma = priv->td0_pool_dma + |
bc667b99 | 496 | priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc); |
5449c685 | 497 | |
bb72dd53 | 498 | /* vir_pool: pvoid type */ |
78e0e853 | 499 | priv->apTD0Rings = vir_pool |
bc667b99 MP |
500 | + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) |
501 | + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc); | |
5449c685 | 502 | |
78e0e853 | 503 | priv->apTD1Rings = vir_pool |
bc667b99 MP |
504 | + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) |
505 | + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) | |
506 | + priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc); | |
5449c685 | 507 | |
78e0e853 | 508 | priv->tx1_bufs = priv->tx0_bufs + |
bc667b99 | 509 | priv->opts.tx_descs[0] * PKT_BUF_SZ; |
5449c685 | 510 | |
78e0e853 | 511 | priv->tx_beacon_bufs = priv->tx1_bufs + |
bc667b99 | 512 | priv->opts.tx_descs[1] * PKT_BUF_SZ; |
5449c685 | 513 | |
78e0e853 | 514 | priv->pbyTmpBuff = priv->tx_beacon_bufs + |
915006cd | 515 | CB_BEACON_BUF_SIZE; |
5449c685 | 516 | |
78e0e853 | 517 | priv->tx_bufs_dma1 = priv->tx_bufs_dma0 + |
bc667b99 | 518 | priv->opts.tx_descs[0] * PKT_BUF_SZ; |
5449c685 | 519 | |
78e0e853 | 520 | priv->tx_beacon_dma = priv->tx_bufs_dma1 + |
bc667b99 | 521 | priv->opts.tx_descs[1] * PKT_BUF_SZ; |
5449c685 | 522 | |
915006cd | 523 | return true; |
5449c685 FB |
524 | } |
525 | ||
78e0e853 | 526 | static void device_free_rings(struct vnt_private *priv) |
84b50762 | 527 | { |
78e0e853 | 528 | dma_free_coherent(&priv->pcid->dev, |
bc667b99 MP |
529 | priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + |
530 | priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + | |
531 | priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + | |
532 | priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), | |
78e0e853 MP |
533 | priv->aRD0Ring, priv->pool_dma); |
534 | ||
535 | if (priv->tx0_bufs) | |
536 | dma_free_coherent(&priv->pcid->dev, | |
bc667b99 MP |
537 | priv->opts.tx_descs[0] * PKT_BUF_SZ + |
538 | priv->opts.tx_descs[1] * PKT_BUF_SZ + | |
78e0e853 MP |
539 | CB_BEACON_BUF_SIZE + |
540 | CB_MAX_BUF_SIZE, | |
541 | priv->tx0_bufs, priv->tx_bufs_dma0); | |
5449c685 FB |
542 | } |
543 | ||
78e0e853 | 544 | static void device_init_rd0_ring(struct vnt_private *priv) |
84b50762 | 545 | { |
915006cd | 546 | int i; |
78e0e853 | 547 | dma_addr_t curr = priv->rd0_pool_dma; |
5e76c8f4 | 548 | struct vnt_rx_desc *desc; |
915006cd JP |
549 | |
550 | /* Init the RD0 ring entries */ | |
bc667b99 | 551 | for (i = 0; i < priv->opts.rx_descs0; |
9cb693f6 | 552 | i ++, curr += sizeof(struct vnt_rx_desc)) { |
5e76c8f4 | 553 | desc = &priv->aRD0Ring[i]; |
e06cf9ab | 554 | desc->rd_info = kzalloc(sizeof(*desc->rd_info), GFP_ATOMIC); |
217ed3ab | 555 | |
5e76c8f4 | 556 | if (!device_alloc_rx_buf(priv, desc)) |
78e0e853 | 557 | dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); |
42f709ef | 558 | |
bc667b99 | 559 | desc->next = &(priv->aRD0Ring[(i+1) % priv->opts.rx_descs0]); |
5e76c8f4 | 560 | desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); |
915006cd JP |
561 | } |
562 | ||
563 | if (i > 0) | |
78e0e853 MP |
564 | priv->aRD0Ring[i-1].next_desc = cpu_to_le32(priv->rd0_pool_dma); |
565 | priv->pCurrRD[0] = &priv->aRD0Ring[0]; | |
5449c685 FB |
566 | } |
567 | ||
78e0e853 | 568 | static void device_init_rd1_ring(struct vnt_private *priv) |
84b50762 | 569 | { |
915006cd | 570 | int i; |
78e0e853 | 571 | dma_addr_t curr = priv->rd1_pool_dma; |
5e76c8f4 | 572 | struct vnt_rx_desc *desc; |
915006cd JP |
573 | |
574 | /* Init the RD1 ring entries */ | |
bc667b99 | 575 | for (i = 0; i < priv->opts.rx_descs1; |
9cb693f6 | 576 | i ++, curr += sizeof(struct vnt_rx_desc)) { |
5e76c8f4 | 577 | desc = &priv->aRD1Ring[i]; |
e06cf9ab | 578 | desc->rd_info = kzalloc(sizeof(*desc->rd_info), GFP_ATOMIC); |
217ed3ab | 579 | |
5e76c8f4 | 580 | if (!device_alloc_rx_buf(priv, desc)) |
78e0e853 | 581 | dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); |
42f709ef | 582 | |
bc667b99 | 583 | desc->next = &(priv->aRD1Ring[(i+1) % priv->opts.rx_descs1]); |
5e76c8f4 | 584 | desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); |
915006cd JP |
585 | } |
586 | ||
587 | if (i > 0) | |
78e0e853 MP |
588 | priv->aRD1Ring[i-1].next_desc = cpu_to_le32(priv->rd1_pool_dma); |
589 | priv->pCurrRD[1] = &priv->aRD1Ring[0]; | |
5449c685 FB |
590 | } |
591 | ||
78e0e853 | 592 | static void device_free_rd0_ring(struct vnt_private *priv) |
84b50762 | 593 | { |
915006cd | 594 | int i; |
5449c685 | 595 | |
bc667b99 | 596 | for (i = 0; i < priv->opts.rx_descs0; i++) { |
5e76c8f4 MP |
597 | struct vnt_rx_desc *desc = &(priv->aRD0Ring[i]); |
598 | struct vnt_rd_info *rd_info = desc->rd_info; | |
5449c685 | 599 | |
78e0e853 MP |
600 | dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma, |
601 | priv->rx_buf_sz, DMA_FROM_DEVICE); | |
5449c685 | 602 | |
88defe2b | 603 | dev_kfree_skb(rd_info->skb); |
5449c685 | 604 | |
5e76c8f4 | 605 | kfree(desc->rd_info); |
915006cd | 606 | } |
5449c685 FB |
607 | } |
608 | ||
78e0e853 | 609 | static void device_free_rd1_ring(struct vnt_private *priv) |
84b50762 | 610 | { |
915006cd | 611 | int i; |
5449c685 | 612 | |
bc667b99 | 613 | for (i = 0; i < priv->opts.rx_descs1; i++) { |
5e76c8f4 MP |
614 | struct vnt_rx_desc *desc = &priv->aRD1Ring[i]; |
615 | struct vnt_rd_info *rd_info = desc->rd_info; | |
5449c685 | 616 | |
78e0e853 MP |
617 | dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma, |
618 | priv->rx_buf_sz, DMA_FROM_DEVICE); | |
5449c685 | 619 | |
88defe2b | 620 | dev_kfree_skb(rd_info->skb); |
5449c685 | 621 | |
5e76c8f4 | 622 | kfree(desc->rd_info); |
915006cd | 623 | } |
5449c685 FB |
624 | } |
625 | ||
78e0e853 | 626 | static void device_init_td0_ring(struct vnt_private *priv) |
84b50762 | 627 | { |
915006cd JP |
628 | int i; |
629 | dma_addr_t curr; | |
5e76c8f4 | 630 | struct vnt_tx_desc *desc; |
915006cd | 631 | |
78e0e853 | 632 | curr = priv->td0_pool_dma; |
bc667b99 | 633 | for (i = 0; i < priv->opts.tx_descs[0]; |
e2357271 | 634 | i++, curr += sizeof(struct vnt_tx_desc)) { |
5e76c8f4 | 635 | desc = &priv->apTD0Rings[i]; |
068b9988 | 636 | desc->td_info = kzalloc(sizeof(*desc->td_info), GFP_ATOMIC); |
217ed3ab | 637 | |
5e76c8f4 MP |
638 | desc->td_info->buf = priv->tx0_bufs + i * PKT_BUF_SZ; |
639 | desc->td_info->buf_dma = priv->tx_bufs_dma0 + i * PKT_BUF_SZ; | |
319755a7 | 640 | |
bc667b99 | 641 | desc->next = &(priv->apTD0Rings[(i+1) % priv->opts.tx_descs[0]]); |
5e76c8f4 | 642 | desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_tx_desc)); |
915006cd JP |
643 | } |
644 | ||
645 | if (i > 0) | |
78e0e853 MP |
646 | priv->apTD0Rings[i-1].next_desc = cpu_to_le32(priv->td0_pool_dma); |
647 | priv->apTailTD[0] = priv->apCurrTD[0] = &priv->apTD0Rings[0]; | |
5449c685 FB |
648 | } |
649 | ||
78e0e853 | 650 | static void device_init_td1_ring(struct vnt_private *priv) |
84b50762 | 651 | { |
915006cd JP |
652 | int i; |
653 | dma_addr_t curr; | |
5e76c8f4 | 654 | struct vnt_tx_desc *desc; |
915006cd JP |
655 | |
656 | /* Init the TD ring entries */ | |
78e0e853 | 657 | curr = priv->td1_pool_dma; |
bc667b99 | 658 | for (i = 0; i < priv->opts.tx_descs[1]; |
e2357271 | 659 | i++, curr += sizeof(struct vnt_tx_desc)) { |
5e76c8f4 | 660 | desc = &priv->apTD1Rings[i]; |
068b9988 | 661 | desc->td_info = kzalloc(sizeof(*desc->td_info), GFP_ATOMIC); |
217ed3ab | 662 | |
5e76c8f4 MP |
663 | desc->td_info->buf = priv->tx1_bufs + i * PKT_BUF_SZ; |
664 | desc->td_info->buf_dma = priv->tx_bufs_dma1 + i * PKT_BUF_SZ; | |
319755a7 | 665 | |
bc667b99 | 666 | desc->next = &(priv->apTD1Rings[(i + 1) % priv->opts.tx_descs[1]]); |
5e76c8f4 | 667 | desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_tx_desc)); |
915006cd JP |
668 | } |
669 | ||
670 | if (i > 0) | |
78e0e853 MP |
671 | priv->apTD1Rings[i-1].next_desc = cpu_to_le32(priv->td1_pool_dma); |
672 | priv->apTailTD[1] = priv->apCurrTD[1] = &priv->apTD1Rings[0]; | |
5449c685 FB |
673 | } |
674 | ||
78e0e853 | 675 | static void device_free_td0_ring(struct vnt_private *priv) |
84b50762 | 676 | { |
915006cd | 677 | int i; |
6b711271 | 678 | |
bc667b99 | 679 | for (i = 0; i < priv->opts.tx_descs[0]; i++) { |
5e76c8f4 | 680 | struct vnt_tx_desc *desc = &priv->apTD0Rings[i]; |
12f2ee35 | 681 | struct vnt_td_info *td_info = desc->td_info; |
5449c685 | 682 | |
12f2ee35 | 683 | dev_kfree_skb(td_info->skb); |
5e76c8f4 | 684 | kfree(desc->td_info); |
915006cd | 685 | } |
5449c685 FB |
686 | } |
687 | ||
78e0e853 | 688 | static void device_free_td1_ring(struct vnt_private *priv) |
84b50762 | 689 | { |
915006cd | 690 | int i; |
5449c685 | 691 | |
bc667b99 | 692 | for (i = 0; i < priv->opts.tx_descs[1]; i++) { |
5e76c8f4 | 693 | struct vnt_tx_desc *desc = &priv->apTD1Rings[i]; |
12f2ee35 | 694 | struct vnt_td_info *td_info = desc->td_info; |
5449c685 | 695 | |
12f2ee35 | 696 | dev_kfree_skb(td_info->skb); |
5e76c8f4 | 697 | kfree(desc->td_info); |
915006cd | 698 | } |
5449c685 FB |
699 | } |
700 | ||
5449c685 FB |
701 | /*-----------------------------------------------------------------*/ |
702 | ||
0924a89b | 703 | static int device_rx_srv(struct vnt_private *priv, unsigned int idx) |
84b50762 | 704 | { |
480fc5b8 | 705 | struct vnt_rx_desc *rd; |
915006cd | 706 | int works = 0; |
5449c685 | 707 | |
0924a89b | 708 | for (rd = priv->pCurrRD[idx]; |
480fc5b8 MP |
709 | rd->rd0.owner == OWNED_BY_HOST; |
710 | rd = rd->next) { | |
915006cd JP |
711 | if (works++ > 15) |
712 | break; | |
b5eeed8c | 713 | |
480fc5b8 | 714 | if (!rd->rd_info->skb) |
b5eeed8c MP |
715 | break; |
716 | ||
480fc5b8 MP |
717 | if (vnt_receive_frame(priv, rd)) { |
718 | if (!device_alloc_rx_buf(priv, rd)) { | |
78e0e853 | 719 | dev_err(&priv->pcid->dev, |
42f709ef | 720 | "can not allocate rx buf\n"); |
915006cd JP |
721 | break; |
722 | } | |
723 | } | |
480fc5b8 | 724 | rd->rd0.owner = OWNED_BY_NIC; |
915006cd JP |
725 | } |
726 | ||
0924a89b | 727 | priv->pCurrRD[idx] = rd; |
915006cd JP |
728 | |
729 | return works; | |
5449c685 FB |
730 | } |
731 | ||
78e0e853 | 732 | static bool device_alloc_rx_buf(struct vnt_private *priv, |
480fc5b8 | 733 | struct vnt_rx_desc *rd) |
84b50762 | 734 | { |
480fc5b8 | 735 | struct vnt_rd_info *rd_info = rd->rd_info; |
5449c685 | 736 | |
5e011b43 MP |
737 | rd_info->skb = dev_alloc_skb((int)priv->rx_buf_sz); |
738 | if (rd_info->skb == NULL) | |
915006cd | 739 | return false; |
33b1c8c1 | 740 | |
5e011b43 | 741 | rd_info->skb_dma = |
78e0e853 | 742 | dma_map_single(&priv->pcid->dev, |
5e011b43 | 743 | skb_put(rd_info->skb, skb_tailroom(rd_info->skb)), |
78e0e853 | 744 | priv->rx_buf_sz, DMA_FROM_DEVICE); |
2fbf6d61 HM |
745 | if (dma_mapping_error(&priv->pcid->dev, rd_info->skb_dma)) { |
746 | dev_kfree_skb(rd_info->skb); | |
747 | rd_info->skb = NULL; | |
748 | return false; | |
749 | } | |
33b1c8c1 | 750 | |
480fc5b8 | 751 | *((unsigned int *)&rd->rd0) = 0; /* FIX cast */ |
915006cd | 752 | |
480fc5b8 MP |
753 | rd->rd0.res_count = cpu_to_le16(priv->rx_buf_sz); |
754 | rd->rd0.owner = OWNED_BY_NIC; | |
755 | rd->rd1.req_count = cpu_to_le16(priv->rx_buf_sz); | |
756 | rd->buff_addr = cpu_to_le32(rd_info->skb_dma); | |
915006cd JP |
757 | |
758 | return true; | |
5449c685 FB |
759 | } |
760 | ||
59918bea MP |
761 | static const u8 fallback_rate0[5][5] = { |
762 | {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M}, | |
763 | {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M}, | |
764 | {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M}, | |
765 | {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M}, | |
766 | {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M} | |
767 | }; | |
768 | ||
769 | static const u8 fallback_rate1[5][5] = { | |
770 | {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M}, | |
771 | {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M}, | |
772 | {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M}, | |
773 | {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M}, | |
774 | {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M} | |
775 | }; | |
776 | ||
777 | static int vnt_int_report_rate(struct vnt_private *priv, | |
54382859 | 778 | struct vnt_td_info *context, u8 tsr0, u8 tsr1) |
59918bea MP |
779 | { |
780 | struct vnt_tx_fifo_head *fifo_head; | |
781 | struct ieee80211_tx_info *info; | |
782 | struct ieee80211_rate *rate; | |
783 | u16 fb_option; | |
784 | u8 tx_retry = (tsr0 & TSR0_NCR); | |
785 | s8 idx; | |
786 | ||
787 | if (!context) | |
788 | return -ENOMEM; | |
789 | ||
790 | if (!context->skb) | |
791 | return -EINVAL; | |
792 | ||
793 | fifo_head = (struct vnt_tx_fifo_head *)context->buf; | |
794 | fb_option = (le16_to_cpu(fifo_head->fifo_ctl) & | |
795 | (FIFOCTL_AUTO_FB_0 | FIFOCTL_AUTO_FB_1)); | |
796 | ||
797 | info = IEEE80211_SKB_CB(context->skb); | |
798 | idx = info->control.rates[0].idx; | |
799 | ||
800 | if (fb_option && !(tsr1 & TSR1_TERR)) { | |
801 | u8 tx_rate; | |
802 | u8 retry = tx_retry; | |
803 | ||
804 | rate = ieee80211_get_tx_rate(priv->hw, info); | |
805 | tx_rate = rate->hw_value - RATE_18M; | |
806 | ||
807 | if (retry > 4) | |
808 | retry = 4; | |
809 | ||
810 | if (fb_option & FIFOCTL_AUTO_FB_0) | |
811 | tx_rate = fallback_rate0[tx_rate][retry]; | |
812 | else if (fb_option & FIFOCTL_AUTO_FB_1) | |
813 | tx_rate = fallback_rate1[tx_rate][retry]; | |
814 | ||
57fbcce3 | 815 | if (info->band == NL80211_BAND_5GHZ) |
59918bea MP |
816 | idx = tx_rate - RATE_6M; |
817 | else | |
818 | idx = tx_rate; | |
819 | } | |
820 | ||
821 | ieee80211_tx_info_clear_status(info); | |
822 | ||
823 | info->status.rates[0].count = tx_retry; | |
824 | ||
825 | if (!(tsr1 & TSR1_TERR)) { | |
826 | info->status.rates[0].idx = idx; | |
6e44dc4b MP |
827 | |
828 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | |
829 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; | |
830 | else | |
831 | info->flags |= IEEE80211_TX_STAT_ACK; | |
59918bea MP |
832 | } |
833 | ||
834 | return 0; | |
835 | } | |
836 | ||
0924a89b | 837 | static int device_tx_srv(struct vnt_private *priv, unsigned int idx) |
84b50762 | 838 | { |
9f31b695 | 839 | struct vnt_tx_desc *desc; |
915006cd JP |
840 | int works = 0; |
841 | unsigned char byTsr0; | |
842 | unsigned char byTsr1; | |
915006cd | 843 | |
0924a89b | 844 | for (desc = priv->apTailTD[idx]; priv->iTDUsed[idx] > 0; desc = desc->next) { |
9f31b695 | 845 | if (desc->td0.owner == OWNED_BY_NIC) |
915006cd JP |
846 | break; |
847 | if (works++ > 15) | |
848 | break; | |
849 | ||
9f31b695 MP |
850 | byTsr0 = desc->td0.tsr0; |
851 | byTsr1 = desc->td0.tsr1; | |
915006cd | 852 | |
bb72dd53 | 853 | /* Only the status of first TD in the chain is correct */ |
9f31b695 MP |
854 | if (desc->td1.tcr & TCR_STP) { |
855 | if ((desc->td_info->flags & TD_FLAGS_NETIF_SKB) != 0) { | |
915006cd JP |
856 | if (!(byTsr1 & TSR1_TERR)) { |
857 | if (byTsr0 != 0) { | |
48caf5a0 | 858 | pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n", |
0924a89b | 859 | (int)idx, byTsr1, |
48caf5a0 | 860 | byTsr0); |
915006cd | 861 | } |
5e0cc8a2 | 862 | } else { |
48caf5a0 | 863 | pr_debug(" Tx[%d] dropped & tsr1[%02X] tsr0[%02X]\n", |
0924a89b | 864 | (int)idx, byTsr1, byTsr0); |
915006cd JP |
865 | } |
866 | } | |
867 | ||
868 | if (byTsr1 & TSR1_TERR) { | |
9f31b695 | 869 | if ((desc->td_info->flags & TD_FLAGS_PRIV_SKB) != 0) { |
48caf5a0 | 870 | pr_debug(" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X]\n", |
0924a89b | 871 | (int)idx, byTsr1, byTsr0); |
915006cd | 872 | } |
915006cd | 873 | } |
ad3fee9b | 874 | |
9f31b695 | 875 | vnt_int_report_rate(priv, desc->td_info, byTsr0, byTsr1); |
ad3fee9b | 876 | |
9f31b695 | 877 | device_free_tx_buf(priv, desc); |
0924a89b | 878 | priv->iTDUsed[idx]--; |
915006cd | 879 | } |
915006cd JP |
880 | } |
881 | ||
0924a89b | 882 | priv->apTailTD[idx] = desc; |
915006cd JP |
883 | |
884 | return works; | |
5449c685 FB |
885 | } |
886 | ||
78e0e853 | 887 | static void device_error(struct vnt_private *priv, unsigned short status) |
84b50762 | 888 | { |
915006cd | 889 | if (status & ISR_FETALERR) { |
78e0e853 | 890 | dev_err(&priv->pcid->dev, "Hardware fatal error\n"); |
42f709ef | 891 | |
f9f853af | 892 | MACbShutdown(priv); |
915006cd JP |
893 | return; |
894 | } | |
5449c685 FB |
895 | } |
896 | ||
78e0e853 | 897 | static void device_free_tx_buf(struct vnt_private *priv, |
5e76c8f4 | 898 | struct vnt_tx_desc *desc) |
84b50762 | 899 | { |
12f2ee35 MP |
900 | struct vnt_td_info *td_info = desc->td_info; |
901 | struct sk_buff *skb = td_info->skb; | |
5449c685 | 902 | |
3fa0917b | 903 | if (skb) |
78e0e853 | 904 | ieee80211_tx_status_irqsafe(priv->hw, skb); |
5449c685 | 905 | |
12f2ee35 MP |
906 | td_info->skb = NULL; |
907 | td_info->flags = 0; | |
5449c685 FB |
908 | } |
909 | ||
64e4fd51 MP |
910 | static void vnt_check_bb_vga(struct vnt_private *priv) |
911 | { | |
912 | long dbm; | |
913 | int i; | |
914 | ||
915 | if (!priv->bUpdateBBVGA) | |
916 | return; | |
917 | ||
918 | if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) | |
919 | return; | |
920 | ||
921 | if (!(priv->vif->bss_conf.assoc && priv->uCurrRSSI)) | |
922 | return; | |
923 | ||
924 | RFvRSSITodBm(priv, (u8)priv->uCurrRSSI, &dbm); | |
925 | ||
926 | for (i = 0; i < BB_VGA_LEVEL; i++) { | |
927 | if (dbm < priv->ldBmThreshold[i]) { | |
928 | priv->byBBVGANew = priv->abyBBVGA[i]; | |
929 | break; | |
930 | } | |
931 | } | |
932 | ||
933 | if (priv->byBBVGANew == priv->byBBVGACurrent) { | |
934 | priv->uBBVGADiffCount = 1; | |
935 | return; | |
936 | } | |
937 | ||
938 | priv->uBBVGADiffCount++; | |
939 | ||
940 | if (priv->uBBVGADiffCount == 1) { | |
941 | /* first VGA diff gain */ | |
942 | BBvSetVGAGainOffset(priv, priv->byBBVGANew); | |
943 | ||
944 | dev_dbg(&priv->pcid->dev, | |
945 | "First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", | |
946 | (int)dbm, priv->byBBVGANew, | |
947 | priv->byBBVGACurrent, | |
948 | (int)priv->uBBVGADiffCount); | |
949 | } | |
950 | ||
951 | if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) { | |
952 | dev_dbg(&priv->pcid->dev, | |
953 | "RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", | |
954 | (int)dbm, priv->byBBVGANew, | |
955 | priv->byBBVGACurrent, | |
956 | (int)priv->uBBVGADiffCount); | |
957 | ||
958 | BBvSetVGAGainOffset(priv, priv->byBBVGANew); | |
959 | } | |
960 | } | |
961 | ||
2995dfe6 | 962 | static void vnt_interrupt_process(struct vnt_private *priv) |
84b50762 | 963 | { |
2995dfe6 | 964 | struct ieee80211_low_level_stats *low_stats = &priv->low_stats; |
915006cd | 965 | int max_count = 0; |
700f6c02 | 966 | u32 mib_counter; |
41b9e5e5 | 967 | u32 isr; |
6cff1f6a | 968 | unsigned long flags; |
915006cd | 969 | |
41b9e5e5 | 970 | MACvReadISR(priv->PortOffset, &isr); |
915006cd | 971 | |
41b9e5e5 | 972 | if (isr == 0) |
ff1ce1a8 | 973 | return; |
915006cd | 974 | |
41b9e5e5 MP |
975 | if (isr == 0xffffffff) { |
976 | pr_debug("isr = 0xffff\n"); | |
ff1ce1a8 | 977 | return; |
915006cd | 978 | } |
915006cd | 979 | |
2995dfe6 | 980 | MACvIntDisable(priv->PortOffset); |
6cff1f6a | 981 | |
2995dfe6 | 982 | spin_lock_irqsave(&priv->lock, flags); |
915006cd | 983 | |
700f6c02 | 984 | /* Read low level stats */ |
2995dfe6 | 985 | MACvReadMIBCounter(priv->PortOffset, &mib_counter); |
700f6c02 MP |
986 | |
987 | low_stats->dot11RTSSuccessCount += mib_counter & 0xff; | |
988 | low_stats->dot11RTSFailureCount += (mib_counter >> 8) & 0xff; | |
989 | low_stats->dot11ACKFailureCount += (mib_counter >> 16) & 0xff; | |
990 | low_stats->dot11FCSErrorCount += (mib_counter >> 24) & 0xff; | |
915006cd | 991 | |
bb72dd53 AS |
992 | /* |
993 | * TBD.... | |
994 | * Must do this after doing rx/tx, cause ISR bit is slow | |
995 | * than RD/TD write back | |
996 | * update ISR counter | |
997 | */ | |
41b9e5e5 MP |
998 | while (isr && priv->vif) { |
999 | MACvWriteISR(priv->PortOffset, isr); | |
915006cd | 1000 | |
41b9e5e5 | 1001 | if (isr & ISR_FETALERR) { |
48caf5a0 | 1002 | pr_debug(" ISR_FETALERR\n"); |
2995dfe6 MP |
1003 | VNSvOutPortB(priv->PortOffset + MAC_REG_SOFTPWRCTL, 0); |
1004 | VNSvOutPortW(priv->PortOffset + | |
1005 | MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI); | |
41b9e5e5 | 1006 | device_error(priv, isr); |
915006cd JP |
1007 | } |
1008 | ||
41b9e5e5 | 1009 | if (isr & ISR_TBTT) { |
2995dfe6 MP |
1010 | if (priv->op_mode != NL80211_IFTYPE_ADHOC) |
1011 | vnt_check_bb_vga(priv); | |
915006cd | 1012 | |
2995dfe6 MP |
1013 | priv->bBeaconSent = false; |
1014 | if (priv->bEnablePSMode) | |
1015 | PSbIsNextTBTTWakeUp((void *)priv); | |
915006cd | 1016 | |
2995dfe6 MP |
1017 | if ((priv->op_mode == NL80211_IFTYPE_AP || |
1018 | priv->op_mode == NL80211_IFTYPE_ADHOC) && | |
1019 | priv->vif->bss_conf.enable_beacon) { | |
f9f853af | 1020 | MACvOneShotTimer1MicroSec(priv, |
2995dfe6 | 1021 | (priv->vif->bss_conf.beacon_int - MAKE_BEACON_RESERVED) << 10); |
915006cd JP |
1022 | } |
1023 | ||
4e8a7e5f | 1024 | /* TODO: adhoc PS mode */ |
915006cd JP |
1025 | |
1026 | } | |
1027 | ||
41b9e5e5 | 1028 | if (isr & ISR_BNTX) { |
2995dfe6 MP |
1029 | if (priv->op_mode == NL80211_IFTYPE_ADHOC) { |
1030 | priv->bIsBeaconBufReadySet = false; | |
1031 | priv->cbBeaconBufReadySetCnt = 0; | |
915006cd JP |
1032 | } |
1033 | ||
2995dfe6 | 1034 | priv->bBeaconSent = true; |
915006cd JP |
1035 | } |
1036 | ||
41b9e5e5 | 1037 | if (isr & ISR_RXDMA0) |
2995dfe6 | 1038 | max_count += device_rx_srv(priv, TYPE_RXDMA0); |
bc5cf656 | 1039 | |
41b9e5e5 | 1040 | if (isr & ISR_RXDMA1) |
2995dfe6 | 1041 | max_count += device_rx_srv(priv, TYPE_RXDMA1); |
bc5cf656 | 1042 | |
41b9e5e5 | 1043 | if (isr & ISR_TXDMA0) |
2995dfe6 | 1044 | max_count += device_tx_srv(priv, TYPE_TXDMA0); |
bc5cf656 | 1045 | |
41b9e5e5 | 1046 | if (isr & ISR_AC0DMA) |
2995dfe6 | 1047 | max_count += device_tx_srv(priv, TYPE_AC0DMA); |
bc5cf656 | 1048 | |
41b9e5e5 | 1049 | if (isr & ISR_SOFTTIMER1) { |
2995dfe6 MP |
1050 | if (priv->vif->bss_conf.enable_beacon) |
1051 | vnt_beacon_make(priv, priv->vif); | |
915006cd JP |
1052 | } |
1053 | ||
54fbb2da | 1054 | /* If both buffers available wake the queue */ |
2995dfe6 MP |
1055 | if (AVAIL_TD(priv, TYPE_TXDMA0) && |
1056 | AVAIL_TD(priv, TYPE_AC0DMA) && | |
1057 | ieee80211_queue_stopped(priv->hw, 0)) | |
1058 | ieee80211_wake_queues(priv->hw); | |
54fbb2da | 1059 | |
41b9e5e5 | 1060 | MACvReadISR(priv->PortOffset, &isr); |
915006cd | 1061 | |
2995dfe6 MP |
1062 | MACvReceive0(priv->PortOffset); |
1063 | MACvReceive1(priv->PortOffset); | |
915006cd | 1064 | |
bc667b99 | 1065 | if (max_count > priv->opts.int_works) |
915006cd JP |
1066 | break; |
1067 | } | |
1068 | ||
2995dfe6 | 1069 | spin_unlock_irqrestore(&priv->lock, flags); |
915006cd | 1070 | |
2995dfe6 | 1071 | MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE); |
ff1ce1a8 MP |
1072 | } |
1073 | ||
1074 | static void vnt_interrupt_work(struct work_struct *work) | |
1075 | { | |
1076 | struct vnt_private *priv = | |
1077 | container_of(work, struct vnt_private, interrupt_work); | |
1078 | ||
1079 | if (priv->vif) | |
1080 | vnt_interrupt_process(priv); | |
1081 | } | |
6cff1f6a | 1082 | |
ff1ce1a8 MP |
1083 | static irqreturn_t vnt_interrupt(int irq, void *arg) |
1084 | { | |
1085 | struct vnt_private *priv = arg; | |
915006cd | 1086 | |
ff1ce1a8 MP |
1087 | if (priv->vif) |
1088 | schedule_work(&priv->interrupt_work); | |
1089 | ||
1090 | return IRQ_HANDLED; | |
5449c685 | 1091 | } |
915006cd | 1092 | |
67013f2c MP |
1093 | static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) |
1094 | { | |
1095 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | |
e2357271 | 1096 | struct vnt_tx_desc *head_td; |
c3125305 | 1097 | u32 dma_idx; |
67013f2c MP |
1098 | unsigned long flags; |
1099 | ||
1100 | spin_lock_irqsave(&priv->lock, flags); | |
1101 | ||
c3125305 MP |
1102 | if (ieee80211_is_data(hdr->frame_control)) |
1103 | dma_idx = TYPE_AC0DMA; | |
1104 | else | |
67013f2c MP |
1105 | dma_idx = TYPE_TXDMA0; |
1106 | ||
1107 | if (AVAIL_TD(priv, dma_idx) < 1) { | |
1108 | spin_unlock_irqrestore(&priv->lock, flags); | |
113d6dc1 | 1109 | ieee80211_stop_queues(priv->hw); |
67013f2c MP |
1110 | return -ENOMEM; |
1111 | } | |
1112 | ||
1113 | head_td = priv->apCurrTD[dma_idx]; | |
1114 | ||
9cc8eac9 | 1115 | head_td->td1.tcr = 0; |
67013f2c | 1116 | |
54382859 | 1117 | head_td->td_info->skb = skb; |
67013f2c | 1118 | |
c3125305 | 1119 | if (dma_idx == TYPE_AC0DMA) |
54382859 | 1120 | head_td->td_info->flags = TD_FLAGS_NETIF_SKB; |
c3125305 | 1121 | |
67013f2c MP |
1122 | priv->apCurrTD[dma_idx] = head_td->next; |
1123 | ||
1124 | spin_unlock_irqrestore(&priv->lock, flags); | |
1125 | ||
1126 | vnt_generate_fifo_header(priv, dma_idx, head_td, skb); | |
1127 | ||
67013f2c MP |
1128 | spin_lock_irqsave(&priv->lock, flags); |
1129 | ||
1130 | priv->bPWBitOn = false; | |
1131 | ||
b5745290 | 1132 | /* Set TSR1 & ReqCount in TxDescHead */ |
9cc8eac9 | 1133 | head_td->td1.tcr |= (TCR_STP | TCR_EDP | EDMSDU); |
54382859 | 1134 | head_td->td1.req_count = cpu_to_le16(head_td->td_info->req_count); |
b5745290 | 1135 | |
54382859 | 1136 | head_td->buff_addr = cpu_to_le32(head_td->td_info->buf_dma); |
187e2a81 | 1137 | |
d65d2b25 MP |
1138 | /* Poll Transmit the adapter */ |
1139 | wmb(); | |
5235ff6a | 1140 | head_td->td0.owner = OWNED_BY_NIC; |
d65d2b25 MP |
1141 | wmb(); /* second memory barrier */ |
1142 | ||
54382859 | 1143 | if (head_td->td_info->flags & TD_FLAGS_NETIF_SKB) |
67013f2c | 1144 | MACvTransmitAC0(priv->PortOffset); |
c3125305 | 1145 | else |
67013f2c MP |
1146 | MACvTransmit0(priv->PortOffset); |
1147 | ||
d65d2b25 MP |
1148 | priv->iTDUsed[dma_idx]++; |
1149 | ||
67013f2c MP |
1150 | spin_unlock_irqrestore(&priv->lock, flags); |
1151 | ||
1152 | return 0; | |
1153 | } | |
1154 | ||
1155 | static void vnt_tx_80211(struct ieee80211_hw *hw, | |
1156 | struct ieee80211_tx_control *control, | |
1157 | struct sk_buff *skb) | |
1158 | { | |
1159 | struct vnt_private *priv = hw->priv; | |
1160 | ||
113d6dc1 | 1161 | if (vnt_tx_packet(priv, skb)) |
67013f2c | 1162 | ieee80211_free_txskb(hw, skb); |
67013f2c MP |
1163 | } |
1164 | ||
1165 | static int vnt_start(struct ieee80211_hw *hw) | |
1166 | { | |
1167 | struct vnt_private *priv = hw->priv; | |
1168 | int ret; | |
1169 | ||
1170 | priv->rx_buf_sz = PKT_BUF_SZ; | |
1171 | if (!device_init_rings(priv)) | |
1172 | return -ENOMEM; | |
1173 | ||
50aefc19 | 1174 | ret = request_irq(priv->pcid->irq, vnt_interrupt, |
67013f2c MP |
1175 | IRQF_SHARED, "vt6655", priv); |
1176 | if (ret) { | |
1177 | dev_dbg(&priv->pcid->dev, "failed to start irq\n"); | |
1178 | return ret; | |
1179 | } | |
1180 | ||
1181 | dev_dbg(&priv->pcid->dev, "call device init rd0 ring\n"); | |
1182 | device_init_rd0_ring(priv); | |
1183 | device_init_rd1_ring(priv); | |
67013f2c MP |
1184 | device_init_td0_ring(priv); |
1185 | device_init_td1_ring(priv); | |
1186 | ||
1187 | device_init_registers(priv); | |
1188 | ||
1189 | dev_dbg(&priv->pcid->dev, "call MACvIntEnable\n"); | |
1190 | MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE); | |
1191 | ||
1192 | ieee80211_wake_queues(hw); | |
1193 | ||
1194 | return 0; | |
1195 | } | |
1196 | ||
1197 | static void vnt_stop(struct ieee80211_hw *hw) | |
1198 | { | |
1199 | struct vnt_private *priv = hw->priv; | |
1200 | ||
1201 | ieee80211_stop_queues(hw); | |
1202 | ||
ff1ce1a8 MP |
1203 | cancel_work_sync(&priv->interrupt_work); |
1204 | ||
f9f853af MP |
1205 | MACbShutdown(priv); |
1206 | MACbSoftwareReset(priv); | |
67013f2c MP |
1207 | CARDbRadioPowerOff(priv); |
1208 | ||
1209 | device_free_td0_ring(priv); | |
1210 | device_free_td1_ring(priv); | |
1211 | device_free_rd0_ring(priv); | |
1212 | device_free_rd1_ring(priv); | |
67013f2c MP |
1213 | device_free_rings(priv); |
1214 | ||
1215 | free_irq(priv->pcid->irq, priv); | |
1216 | } | |
1217 | ||
1218 | static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |
1219 | { | |
1220 | struct vnt_private *priv = hw->priv; | |
1221 | ||
1222 | priv->vif = vif; | |
1223 | ||
1224 | switch (vif->type) { | |
1225 | case NL80211_IFTYPE_STATION: | |
67013f2c MP |
1226 | break; |
1227 | case NL80211_IFTYPE_ADHOC: | |
1228 | MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST); | |
1229 | ||
1230 | MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); | |
1231 | ||
1232 | break; | |
1233 | case NL80211_IFTYPE_AP: | |
1234 | MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST); | |
1235 | ||
1236 | MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); | |
1237 | ||
1238 | break; | |
1239 | default: | |
1240 | return -EOPNOTSUPP; | |
1241 | } | |
1242 | ||
1243 | priv->op_mode = vif->type; | |
1244 | ||
1245 | return 0; | |
1246 | } | |
1247 | ||
1248 | static void vnt_remove_interface(struct ieee80211_hw *hw, | |
1249 | struct ieee80211_vif *vif) | |
1250 | { | |
1251 | struct vnt_private *priv = hw->priv; | |
1252 | ||
1253 | switch (vif->type) { | |
1254 | case NL80211_IFTYPE_STATION: | |
67013f2c MP |
1255 | break; |
1256 | case NL80211_IFTYPE_ADHOC: | |
1257 | MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); | |
1258 | MACvRegBitsOff(priv->PortOffset, | |
1259 | MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); | |
1260 | MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); | |
1261 | break; | |
1262 | case NL80211_IFTYPE_AP: | |
1263 | MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); | |
1264 | MACvRegBitsOff(priv->PortOffset, | |
1265 | MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); | |
1266 | MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); | |
1267 | break; | |
1268 | default: | |
1269 | break; | |
1270 | } | |
1271 | ||
1272 | priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; | |
1273 | } | |
1274 | ||
1275 | ||
1276 | static int vnt_config(struct ieee80211_hw *hw, u32 changed) | |
1277 | { | |
1278 | struct vnt_private *priv = hw->priv; | |
1279 | struct ieee80211_conf *conf = &hw->conf; | |
1280 | u8 bb_type; | |
1281 | ||
1282 | if (changed & IEEE80211_CONF_CHANGE_PS) { | |
1283 | if (conf->flags & IEEE80211_CONF_PS) | |
1284 | PSvEnablePowerSaving(priv, conf->listen_interval); | |
1285 | else | |
1286 | PSvDisablePowerSaving(priv); | |
1287 | } | |
1288 | ||
1289 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || | |
1290 | (conf->flags & IEEE80211_CONF_OFFCHANNEL)) { | |
d7a4cfa8 | 1291 | set_channel(priv, conf->chandef.chan); |
67013f2c | 1292 | |
57fbcce3 | 1293 | if (conf->chandef.chan->band == NL80211_BAND_5GHZ) |
67013f2c MP |
1294 | bb_type = BB_TYPE_11A; |
1295 | else | |
1296 | bb_type = BB_TYPE_11G; | |
1297 | ||
1298 | if (priv->byBBType != bb_type) { | |
1299 | priv->byBBType = bb_type; | |
1300 | ||
bfb6c863 | 1301 | CARDbSetPhyParameter(priv, priv->byBBType); |
67013f2c MP |
1302 | } |
1303 | } | |
1304 | ||
1305 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | |
1306 | if (priv->byBBType == BB_TYPE_11B) | |
1307 | priv->wCurrentRate = RATE_1M; | |
1308 | else | |
1309 | priv->wCurrentRate = RATE_54M; | |
1310 | ||
1311 | RFbSetPower(priv, priv->wCurrentRate, | |
1312 | conf->chandef.chan->hw_value); | |
1313 | } | |
1314 | ||
1315 | return 0; | |
1316 | } | |
1317 | ||
1318 | static void vnt_bss_info_changed(struct ieee80211_hw *hw, | |
1319 | struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, | |
1320 | u32 changed) | |
1321 | { | |
1322 | struct vnt_private *priv = hw->priv; | |
1323 | ||
1324 | priv->current_aid = conf->aid; | |
1325 | ||
8e8e9198 | 1326 | if (changed & BSS_CHANGED_BSSID && conf->bssid) { |
664a5c1d MP |
1327 | unsigned long flags; |
1328 | ||
1329 | spin_lock_irqsave(&priv->lock, flags); | |
1330 | ||
67013f2c MP |
1331 | MACvWriteBSSIDAddress(priv->PortOffset, (u8 *)conf->bssid); |
1332 | ||
664a5c1d MP |
1333 | spin_unlock_irqrestore(&priv->lock, flags); |
1334 | } | |
1335 | ||
67013f2c MP |
1336 | if (changed & BSS_CHANGED_BASIC_RATES) { |
1337 | priv->basic_rates = conf->basic_rates; | |
1338 | ||
1339 | CARDvUpdateBasicTopRate(priv); | |
1340 | ||
1341 | dev_dbg(&priv->pcid->dev, | |
1342 | "basic rates %x\n", conf->basic_rates); | |
1343 | } | |
1344 | ||
1345 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | |
1346 | if (conf->use_short_preamble) { | |
1347 | MACvEnableBarkerPreambleMd(priv->PortOffset); | |
1348 | priv->byPreambleType = true; | |
1349 | } else { | |
1350 | MACvDisableBarkerPreambleMd(priv->PortOffset); | |
1351 | priv->byPreambleType = false; | |
1352 | } | |
1353 | } | |
1354 | ||
1355 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | |
1356 | if (conf->use_cts_prot) | |
1357 | MACvEnableProtectMD(priv->PortOffset); | |
1358 | else | |
1359 | MACvDisableProtectMD(priv->PortOffset); | |
1360 | } | |
1361 | ||
1362 | if (changed & BSS_CHANGED_ERP_SLOT) { | |
1363 | if (conf->use_short_slot) | |
1364 | priv->bShortSlotTime = true; | |
1365 | else | |
1366 | priv->bShortSlotTime = false; | |
1367 | ||
bfb6c863 | 1368 | CARDbSetPhyParameter(priv, priv->byBBType); |
67013f2c MP |
1369 | BBvSetVGAGainOffset(priv, priv->abyBBVGA[0]); |
1370 | } | |
1371 | ||
1372 | if (changed & BSS_CHANGED_TXPOWER) | |
1373 | RFbSetPower(priv, priv->wCurrentRate, | |
1374 | conf->chandef.chan->hw_value); | |
1375 | ||
1376 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | |
1377 | dev_dbg(&priv->pcid->dev, | |
1378 | "Beacon enable %d\n", conf->enable_beacon); | |
1379 | ||
1380 | if (conf->enable_beacon) { | |
1381 | vnt_beacon_enable(priv, vif, conf); | |
1382 | ||
84c00afe MK |
1383 | MACvRegBitsOn(priv->PortOffset, MAC_REG_TCR, |
1384 | TCR_AUTOBCNTX); | |
67013f2c | 1385 | } else { |
84c00afe MK |
1386 | MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, |
1387 | TCR_AUTOBCNTX); | |
67013f2c MP |
1388 | } |
1389 | } | |
1390 | ||
1f171240 MP |
1391 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && |
1392 | priv->op_mode != NL80211_IFTYPE_AP) { | |
1393 | if (conf->assoc && conf->beacon_rate) { | |
67013f2c | 1394 | CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, |
032ed34a | 1395 | conf->sync_tsf); |
67013f2c MP |
1396 | |
1397 | CARDbSetBeaconPeriod(priv, conf->beacon_int); | |
1398 | ||
738487ff | 1399 | CARDvSetFirstNextTBTT(priv, conf->beacon_int); |
c7b14ea0 MP |
1400 | } else { |
1401 | VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, | |
1402 | TFTCTL_TSFCNTRST); | |
1403 | VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, | |
1404 | TFTCTL_TSFCNTREN); | |
67013f2c MP |
1405 | } |
1406 | } | |
1407 | } | |
1408 | ||
1409 | static u64 vnt_prepare_multicast(struct ieee80211_hw *hw, | |
1410 | struct netdev_hw_addr_list *mc_list) | |
1411 | { | |
1412 | struct vnt_private *priv = hw->priv; | |
1413 | struct netdev_hw_addr *ha; | |
1414 | u64 mc_filter = 0; | |
1415 | u32 bit_nr = 0; | |
1416 | ||
1417 | netdev_hw_addr_list_for_each(ha, mc_list) { | |
1418 | bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
1419 | ||
1420 | mc_filter |= 1ULL << (bit_nr & 0x3f); | |
1421 | } | |
1422 | ||
1423 | priv->mc_list_count = mc_list->count; | |
1424 | ||
1425 | return mc_filter; | |
1426 | } | |
1427 | ||
1428 | static void vnt_configure(struct ieee80211_hw *hw, | |
1429 | unsigned int changed_flags, unsigned int *total_flags, u64 multicast) | |
1430 | { | |
1431 | struct vnt_private *priv = hw->priv; | |
1432 | u8 rx_mode = 0; | |
1433 | ||
df140465 | 1434 | *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC; |
67013f2c MP |
1435 | |
1436 | VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode); | |
1437 | ||
1438 | dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode); | |
1439 | ||
67013f2c MP |
1440 | if (changed_flags & FIF_ALLMULTI) { |
1441 | if (*total_flags & FIF_ALLMULTI) { | |
95775d12 MP |
1442 | unsigned long flags; |
1443 | ||
1444 | spin_lock_irqsave(&priv->lock, flags); | |
1445 | ||
67013f2c MP |
1446 | if (priv->mc_list_count > 2) { |
1447 | MACvSelectPage1(priv->PortOffset); | |
1448 | ||
1449 | VNSvOutPortD(priv->PortOffset + | |
1450 | MAC_REG_MAR0, 0xffffffff); | |
1451 | VNSvOutPortD(priv->PortOffset + | |
1452 | MAC_REG_MAR0 + 4, 0xffffffff); | |
1453 | ||
1454 | MACvSelectPage0(priv->PortOffset); | |
1455 | } else { | |
1456 | MACvSelectPage1(priv->PortOffset); | |
1457 | ||
1458 | VNSvOutPortD(priv->PortOffset + | |
1459 | MAC_REG_MAR0, (u32)multicast); | |
1460 | VNSvOutPortD(priv->PortOffset + | |
1461 | MAC_REG_MAR0 + 4, | |
1462 | (u32)(multicast >> 32)); | |
1463 | ||
1464 | MACvSelectPage0(priv->PortOffset); | |
1465 | } | |
1466 | ||
95775d12 MP |
1467 | spin_unlock_irqrestore(&priv->lock, flags); |
1468 | ||
67013f2c MP |
1469 | rx_mode |= RCR_MULTICAST | RCR_BROADCAST; |
1470 | } else { | |
1471 | rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST); | |
1472 | } | |
1473 | } | |
1474 | ||
1475 | if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) { | |
1476 | rx_mode |= RCR_MULTICAST | RCR_BROADCAST; | |
1477 | ||
1478 | if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) | |
1479 | rx_mode &= ~RCR_BSSID; | |
1480 | else | |
1481 | rx_mode |= RCR_BSSID; | |
1482 | } | |
1483 | ||
1484 | VNSvOutPortB(priv->PortOffset + MAC_REG_RCR, rx_mode); | |
1485 | ||
1486 | dev_dbg(&priv->pcid->dev, "rx mode out= %x\n", rx_mode); | |
1487 | } | |
1488 | ||
1489 | static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |
1490 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | |
1491 | struct ieee80211_key_conf *key) | |
1492 | { | |
1493 | struct vnt_private *priv = hw->priv; | |
1494 | ||
1495 | switch (cmd) { | |
1496 | case SET_KEY: | |
1497 | if (vnt_set_keys(hw, sta, vif, key)) | |
1498 | return -EOPNOTSUPP; | |
1499 | break; | |
1500 | case DISABLE_KEY: | |
1501 | if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) | |
1502 | clear_bit(key->hw_key_idx, &priv->key_entry_inuse); | |
1503 | default: | |
1504 | break; | |
1505 | } | |
1506 | ||
1507 | return 0; | |
1508 | } | |
1509 | ||
700f6c02 MP |
1510 | static int vnt_get_stats(struct ieee80211_hw *hw, |
1511 | struct ieee80211_low_level_stats *stats) | |
1512 | { | |
1513 | struct vnt_private *priv = hw->priv; | |
1514 | ||
1515 | memcpy(stats, &priv->low_stats, sizeof(*stats)); | |
1516 | ||
1517 | return 0; | |
1518 | } | |
1519 | ||
67013f2c MP |
1520 | static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
1521 | { | |
1522 | struct vnt_private *priv = hw->priv; | |
1523 | u64 tsf; | |
1524 | ||
738487ff | 1525 | CARDbGetCurrentTSF(priv, &tsf); |
67013f2c MP |
1526 | |
1527 | return tsf; | |
1528 | } | |
1529 | ||
1530 | static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
1531 | u64 tsf) | |
1532 | { | |
1533 | struct vnt_private *priv = hw->priv; | |
1534 | ||
738487ff | 1535 | CARDvUpdateNextTBTT(priv, tsf, vif->bss_conf.beacon_int); |
67013f2c MP |
1536 | } |
1537 | ||
1538 | static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |
1539 | { | |
1540 | struct vnt_private *priv = hw->priv; | |
1541 | ||
1542 | /* reset TSF counter */ | |
1543 | VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); | |
1544 | } | |
1545 | ||
1546 | static const struct ieee80211_ops vnt_mac_ops = { | |
1547 | .tx = vnt_tx_80211, | |
1548 | .start = vnt_start, | |
1549 | .stop = vnt_stop, | |
1550 | .add_interface = vnt_add_interface, | |
1551 | .remove_interface = vnt_remove_interface, | |
1552 | .config = vnt_config, | |
1553 | .bss_info_changed = vnt_bss_info_changed, | |
1554 | .prepare_multicast = vnt_prepare_multicast, | |
1555 | .configure_filter = vnt_configure, | |
1556 | .set_key = vnt_set_key, | |
700f6c02 | 1557 | .get_stats = vnt_get_stats, |
67013f2c MP |
1558 | .get_tsf = vnt_get_tsf, |
1559 | .set_tsf = vnt_set_tsf, | |
1560 | .reset_tsf = vnt_reset_tsf, | |
1561 | }; | |
1562 | ||
b7c9cd45 | 1563 | static int vnt_init(struct vnt_private *priv) |
67013f2c MP |
1564 | { |
1565 | SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr); | |
1566 | ||
3d75b9e2 MP |
1567 | vnt_init_bands(priv); |
1568 | ||
67013f2c MP |
1569 | if (ieee80211_register_hw(priv->hw)) |
1570 | return -ENODEV; | |
1571 | ||
1572 | priv->mac_hw = true; | |
1573 | ||
1574 | CARDbRadioPowerOff(priv); | |
1575 | ||
1576 | return 0; | |
1577 | } | |
1578 | ||
1579 | static int | |
1580 | vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) | |
1581 | { | |
67013f2c MP |
1582 | struct vnt_private *priv; |
1583 | struct ieee80211_hw *hw; | |
1584 | struct wiphy *wiphy; | |
1585 | int rc; | |
1586 | ||
1587 | dev_notice(&pcid->dev, | |
1588 | "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION); | |
1589 | ||
1590 | dev_notice(&pcid->dev, | |
1591 | "Copyright (c) 2003 VIA Networking Technologies, Inc.\n"); | |
1592 | ||
1593 | hw = ieee80211_alloc_hw(sizeof(*priv), &vnt_mac_ops); | |
1594 | if (!hw) { | |
1595 | dev_err(&pcid->dev, "could not register ieee80211_hw\n"); | |
1596 | return -ENOMEM; | |
1597 | } | |
1598 | ||
1599 | priv = hw->priv; | |
f3179826 | 1600 | priv->pcid = pcid; |
67013f2c | 1601 | |
f3179826 | 1602 | spin_lock_init(&priv->lock); |
67013f2c MP |
1603 | |
1604 | priv->hw = hw; | |
1605 | ||
1606 | SET_IEEE80211_DEV(priv->hw, &pcid->dev); | |
1607 | ||
1608 | if (pci_enable_device(pcid)) { | |
1609 | device_free_info(priv); | |
1610 | return -ENODEV; | |
1611 | } | |
1612 | ||
1613 | dev_dbg(&pcid->dev, | |
1614 | "Before get pci_info memaddr is %x\n", priv->memaddr); | |
1615 | ||
a03b8b3e | 1616 | pci_set_master(pcid); |
67013f2c | 1617 | |
a03b8b3e MP |
1618 | priv->memaddr = pci_resource_start(pcid, 0); |
1619 | priv->ioaddr = pci_resource_start(pcid, 1); | |
67013f2c | 1620 | priv->PortOffset = ioremap(priv->memaddr & PCI_BASE_ADDRESS_MEM_MASK, |
319755a7 | 1621 | 256); |
67013f2c MP |
1622 | if (!priv->PortOffset) { |
1623 | dev_err(&pcid->dev, ": Failed to IO remapping ..\n"); | |
1624 | device_free_info(priv); | |
1625 | return -ENODEV; | |
1626 | } | |
1627 | ||
1628 | rc = pci_request_regions(pcid, DEVICE_NAME); | |
1629 | if (rc) { | |
1630 | dev_err(&pcid->dev, ": Failed to find PCI device\n"); | |
1631 | device_free_info(priv); | |
1632 | return -ENODEV; | |
1633 | } | |
1634 | ||
d5806c53 MP |
1635 | if (dma_set_mask(&pcid->dev, DMA_BIT_MASK(32))) { |
1636 | dev_err(&pcid->dev, ": Failed to set dma 32 bit mask\n"); | |
1637 | device_free_info(priv); | |
1638 | return -ENODEV; | |
1639 | } | |
1640 | ||
ff1ce1a8 MP |
1641 | INIT_WORK(&priv->interrupt_work, vnt_interrupt_work); |
1642 | ||
67013f2c | 1643 | /* do reset */ |
f9f853af | 1644 | if (!MACbSoftwareReset(priv)) { |
67013f2c MP |
1645 | dev_err(&pcid->dev, ": Failed to access MAC hardware..\n"); |
1646 | device_free_info(priv); | |
1647 | return -ENODEV; | |
1648 | } | |
1649 | /* initial to reload eeprom */ | |
f9f853af | 1650 | MACvInitialize(priv); |
67013f2c MP |
1651 | MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr); |
1652 | ||
1f51d580 MP |
1653 | /* Get RFType */ |
1654 | priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE); | |
1655 | priv->byRFType &= RF_MASK; | |
1656 | ||
1657 | dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType); | |
1658 | ||
67013f2c MP |
1659 | device_get_options(priv); |
1660 | device_set_options(priv); | |
67013f2c MP |
1661 | |
1662 | wiphy = priv->hw->wiphy; | |
1663 | ||
1664 | wiphy->frag_threshold = FRAG_THRESH_DEF; | |
1665 | wiphy->rts_threshold = RTS_THRESH_DEF; | |
1666 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | |
1667 | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); | |
1668 | ||
30686bf7 JB |
1669 | ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY); |
1670 | ieee80211_hw_set(priv->hw, SIGNAL_DBM); | |
1671 | ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); | |
1672 | ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); | |
eda01f61 | 1673 | ieee80211_hw_set(priv->hw, SUPPORTS_PS); |
67013f2c MP |
1674 | |
1675 | priv->hw->max_signal = 100; | |
1676 | ||
1677 | if (vnt_init(priv)) | |
1678 | return -ENODEV; | |
1679 | ||
1680 | device_print_info(priv); | |
1681 | pci_set_drvdata(pcid, priv); | |
1682 | ||
1683 | return 0; | |
1684 | } | |
1685 | ||
5449c685 | 1686 | /*------------------------------------------------------------------*/ |
5449c685 | 1687 | |
000fe0f5 MP |
1688 | #ifdef CONFIG_PM |
1689 | static int vt6655_suspend(struct pci_dev *pcid, pm_message_t state) | |
1690 | { | |
1691 | struct vnt_private *priv = pci_get_drvdata(pcid); | |
1692 | unsigned long flags; | |
1693 | ||
1694 | spin_lock_irqsave(&priv->lock, flags); | |
1695 | ||
1696 | pci_save_state(pcid); | |
1697 | ||
f9f853af | 1698 | MACbShutdown(priv); |
000fe0f5 MP |
1699 | |
1700 | pci_disable_device(pcid); | |
1701 | pci_set_power_state(pcid, pci_choose_state(pcid, state)); | |
1702 | ||
1703 | spin_unlock_irqrestore(&priv->lock, flags); | |
1704 | ||
1705 | return 0; | |
1706 | } | |
1707 | ||
1708 | static int vt6655_resume(struct pci_dev *pcid) | |
1709 | { | |
1710 | ||
1711 | pci_set_power_state(pcid, PCI_D0); | |
1712 | pci_enable_wake(pcid, PCI_D0, 0); | |
1713 | pci_restore_state(pcid); | |
1714 | ||
1715 | return 0; | |
1716 | } | |
1717 | #endif | |
1718 | ||
013a468c | 1719 | MODULE_DEVICE_TABLE(pci, vt6655_pci_id_table); |
5449c685 FB |
1720 | |
1721 | static struct pci_driver device_driver = { | |
34381c22 PH |
1722 | .name = DEVICE_NAME, |
1723 | .id_table = vt6655_pci_id_table, | |
1724 | .probe = vt6655_probe, | |
1725 | .remove = vt6655_remove, | |
5449c685 | 1726 | #ifdef CONFIG_PM |
000fe0f5 MP |
1727 | .suspend = vt6655_suspend, |
1728 | .resume = vt6655_resume, | |
5449c685 | 1729 | #endif |
5449c685 FB |
1730 | }; |
1731 | ||
e75e8cac | 1732 | module_pci_driver(device_driver); |