pci.c 53.1 KB
Newer Older
Larry Finger's avatar
Larry Finger committed
1
2
/******************************************************************************
 *
Larry Finger's avatar
Larry Finger committed
3
 * Copyright(c) 2009-2012  Realtek Corporation.
Larry Finger's avatar
Larry Finger committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * wlanfae <wlanfae@realtek.com>
 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
 * Hsinchu 300, Taiwan.
 *
 * Larry Finger <Larry.Finger@lwfinger.net>
 *
 *****************************************************************************/

#include "wifi.h"
31
#include "core.h"
Larry Finger's avatar
Larry Finger committed
32
33
34
#include "pci.h"
#include "base.h"
#include "ps.h"
35
#include "efuse.h"
36
#include <linux/export.h>
Larry Finger's avatar
Larry Finger committed
37
38

static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
Jon Mason's avatar
Jon Mason committed
39
40
41
42
	PCI_VENDOR_ID_INTEL,
	PCI_VENDOR_ID_ATI,
	PCI_VENDOR_ID_AMD,
	PCI_VENDOR_ID_SI
Larry Finger's avatar
Larry Finger committed
43
44
};

45
46
47
48
49
50
51
static const u8 ac_to_hwq[] = {
	VO_QUEUE,
	VI_QUEUE,
	BE_QUEUE,
	BK_QUEUE
};

52
static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
53
54
55
		       struct sk_buff *skb)
{
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
56
	__le16 fc = rtl_get_fc(skb);
57
58
59
60
61
62
63
64
65
66
67
68
69
	u8 queue_index = skb_get_queue_mapping(skb);

	if (unlikely(ieee80211_is_beacon(fc)))
		return BEACON_QUEUE;
	if (ieee80211_is_mgmt(fc))
		return MGNT_QUEUE;
	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
		if (ieee80211_is_nullfunc(fc))
			return HIGH_QUEUE;

	return ac_to_hwq[queue_index];
}

Larry Finger's avatar
Larry Finger committed
70
71
72
73
74
75
76
77
/* Update PCI dependent default settings*/
static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
78
	u8 init_aspm;
Larry Finger's avatar
Larry Finger committed
79
80

	ppsc->reg_rfps_level = 0;
81
	ppsc->support_aspm = false;
Larry Finger's avatar
Larry Finger committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

	/*Update PCI ASPM setting */
	ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm;
	switch (rtlpci->const_pci_aspm) {
	case 0:
		/*No ASPM */
		break;

	case 1:
		/*ASPM dynamically enabled/disable. */
		ppsc->reg_rfps_level |= RT_RF_LPS_LEVEL_ASPM;
		break;

	case 2:
		/*ASPM with Clock Req dynamically enabled/disable. */
		ppsc->reg_rfps_level |= (RT_RF_LPS_LEVEL_ASPM |
					 RT_RF_OFF_LEVL_CLK_REQ);
		break;

	case 3:
		/*
		 * Always enable ASPM and Clock Req
		 * from initialization to halt.
		 * */
		ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM);
		ppsc->reg_rfps_level |= (RT_RF_PS_LEVEL_ALWAYS_ASPM |
					 RT_RF_OFF_LEVL_CLK_REQ);
		break;

	case 4:
		/*
		 * Always enable ASPM without Clock Req
		 * from initialization to halt.
		 * */
		ppsc->reg_rfps_level &= ~(RT_RF_LPS_LEVEL_ASPM |
					  RT_RF_OFF_LEVL_CLK_REQ);
		ppsc->reg_rfps_level |= RT_RF_PS_LEVEL_ALWAYS_ASPM;
		break;
	}

	ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;

	/*Update Radio OFF setting */
	switch (rtlpci->const_hwsw_rfoff_d3) {
	case 1:
		if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
			ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
		break;

	case 2:
		if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM)
			ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_ASPM;
		ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_HALT_NIC;
		break;

	case 3:
		ppsc->reg_rfps_level |= RT_RF_OFF_LEVL_PCI_D3;
		break;
	}

	/*Set HW definition to determine if it supports ASPM. */
	switch (rtlpci->const_support_pciaspm) {
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
	case 0:{
			/*Not support ASPM. */
			bool support_aspm = false;
			ppsc->support_aspm = support_aspm;
			break;
		}
	case 1:{
			/*Support ASPM. */
			bool support_aspm = true;
			bool support_backdoor = true;
			ppsc->support_aspm = support_aspm;

			/*if (priv->oem_id == RT_CID_TOSHIBA &&
			   !priv->ndis_adapter.amd_l1_patch)
			   support_backdoor = false; */

			ppsc->support_backdoor = support_backdoor;

			break;
		}
Larry Finger's avatar
Larry Finger committed
164
165
	case 2:
		/*ASPM value set by chipset. */
166
167
168
169
		if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
			bool support_aspm = true;
			ppsc->support_aspm = support_aspm;
		}
Larry Finger's avatar
Larry Finger committed
170
171
172
		break;
	default:
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
173
			 "switch case not processed\n");
Larry Finger's avatar
Larry Finger committed
174
175
		break;
	}
176
177
178
179
180
181
182
183
184

	/* toshiba aspm issue, toshiba will set aspm selfly
	 * so we should not set aspm in driver */
	pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
	if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
		init_aspm == 0x43)
		ppsc->support_aspm = false;
}

Larry Finger's avatar
Larry Finger committed
185
186
187
188
189
static bool _rtl_pci_platform_switch_device_pci_aspm(
			struct ieee80211_hw *hw,
			u8 value)
{
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
190
191
192
193
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));

	if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
		value |= 0x40;
Larry Finger's avatar
Larry Finger committed
194
195
196

	pci_write_config_byte(rtlpci->pdev, 0x80, value);

197
	return false;
Larry Finger's avatar
Larry Finger committed
198
199
200
}

/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
201
static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
Larry Finger's avatar
Larry Finger committed
202
203
{
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
204
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger's avatar
Larry Finger committed
205
206
207

	pci_write_config_byte(rtlpci->pdev, 0x81, value);

208
209
	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
		udelay(100);
Larry Finger's avatar
Larry Finger committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
}

/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
	u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
	/*Retrieve original configuration settings. */
	u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
	u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
				pcibridge_linkctrlreg;
	u16 aspmlevel = 0;
226
	u8 tmp_u1b = 0;
Larry Finger's avatar
Larry Finger committed
227

228
229
230
	if (!ppsc->support_aspm)
		return;

Larry Finger's avatar
Larry Finger committed
231
232
	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
233
			 "PCI(Bridge) UNKNOWN\n");
Larry Finger's avatar
Larry Finger committed
234
235
236
237
238
239
240
241
242

		return;
	}

	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
		RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
		_rtl_pci_switch_clk_req(hw, 0x0);
	}

243
244
	/*for promising device will in L0 state after an I/O. */
	pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
Larry Finger's avatar
Larry Finger committed
245
246
247
248
249
250
251
252
253
254

	/*Set corresponding value. */
	aspmlevel |= BIT(0) | BIT(1);
	linkctrl_reg &= ~aspmlevel;
	pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1));

	_rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg);
	udelay(50);

	/*4 Disable Pci Bridge ASPM */
255
256
	pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
			      pcibridge_linkctrlreg);
Larry Finger's avatar
Larry Finger committed
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

	udelay(50);
}

/*
 *Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for
 *power saving We should follow the sequence to enable
 *RTL8192SE first then enable Pci Bridge ASPM
 *or the system will show bluescreen.
 */
static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
	u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
	u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
	u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
	u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
	u16 aspmlevel;
	u8 u_pcibridge_aspmsetting;
	u8 u_device_aspmsetting;

282
283
284
	if (!ppsc->support_aspm)
		return;

Larry Finger's avatar
Larry Finger committed
285
286
	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
287
			 "PCI(Bridge) UNKNOWN\n");
Larry Finger's avatar
Larry Finger committed
288
289
290
291
292
293
294
295
296
297
298
299
		return;
	}

	/*4 Enable Pci Bridge ASPM */

	u_pcibridge_aspmsetting =
	    pcipriv->ndis_adapter.pcibridge_linkctrlreg |
	    rtlpci->const_hostpci_aspm_setting;

	if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
		u_pcibridge_aspmsetting &= ~BIT(0);

300
301
	pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
			      u_pcibridge_aspmsetting);
Larry Finger's avatar
Larry Finger committed
302
303

	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
304
305
306
307
		 "PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
		 pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
		 (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
		 u_pcibridge_aspmsetting);
Larry Finger's avatar
Larry Finger committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

	udelay(50);

	/*Get ASPM level (with/without Clock Req) */
	aspmlevel = rtlpci->const_devicepci_aspm_setting;
	u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg;

	/*_rtl_pci_platform_switch_device_pci_aspm(dev,*/
	/*(priv->ndis_adapter.linkctrl_reg | ASPMLevel)); */

	u_device_aspmsetting |= aspmlevel;

	_rtl_pci_platform_switch_device_pci_aspm(hw, u_device_aspmsetting);

	if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
		_rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level &
					     RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
		RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
	}
327
	udelay(100);
Larry Finger's avatar
Larry Finger committed
328
329
330
331
}

static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
{
332
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
Larry Finger's avatar
Larry Finger committed
333
334
335
336
337

	bool status = false;
	u8 offset_e0;
	unsigned offset_e4;

338
	pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0);
Larry Finger's avatar
Larry Finger committed
339

340
	pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0);
Larry Finger's avatar
Larry Finger committed
341
342

	if (offset_e0 == 0xA0) {
343
		pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4);
Larry Finger's avatar
Larry Finger committed
344
345
346
347
348
349
350
		if (offset_e4 & BIT(23))
			status = true;
	}

	return status;
}

351
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
Larry Finger's avatar
Larry Finger committed
352
353
{
	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
354
	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
Larry Finger's avatar
Larry Finger committed
355
356
	u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
	u8 linkctrl_reg;
357
	u8 num4bbytes;
Larry Finger's avatar
Larry Finger committed
358

359
	num4bbytes = (capabilityoffset + 0x10) / 4;
Larry Finger's avatar
Larry Finger committed
360
361

	/*Read  Link Control Register */
362
	pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg);
Larry Finger's avatar
Larry Finger committed
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

	pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
}

static void rtl_pci_parse_configuration(struct pci_dev *pdev,
		struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);

	u8 tmp;
	int pos;
	u8 linkctrl_reg;

	/*Link Control Register */
378
	pos = pci_pcie_cap(pdev);
Larry Finger's avatar
Larry Finger committed
379
380
381
	pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
	pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;

382
383
	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n",
		 pcipriv->ndis_adapter.linkctrl_reg);
Larry Finger's avatar
Larry Finger committed
384
385
386
387
388
389
390
391
392

	pci_read_config_byte(pdev, 0x98, &tmp);
	tmp |= BIT(4);
	pci_write_config_byte(pdev, 0x98, tmp);

	tmp = 0x17;
	pci_write_config_byte(pdev, 0x70f, tmp);
}

393
static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
Larry Finger's avatar
Larry Finger committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
{
	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));

	_rtl_pci_update_default_setting(hw);

	if (ppsc->reg_rfps_level & RT_RF_PS_LEVEL_ALWAYS_ASPM) {
		/*Always enable ASPM & Clock Req. */
		rtl_pci_enable_aspm(hw);
		RT_SET_PS_LEVEL(ppsc, RT_RF_PS_LEVEL_ALWAYS_ASPM);
	}

}

static void _rtl_pci_io_handler_init(struct device *dev,
				     struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);

	rtlpriv->io.dev = dev;

	rtlpriv->io.write8_async = pci_write8_async;
	rtlpriv->io.write16_async = pci_write16_async;
	rtlpriv->io.write32_async = pci_write32_async;

	rtlpriv->io.read8_sync = pci_read8_sync;
	rtlpriv->io.read16_sync = pci_read16_sync;
	rtlpriv->io.read32_sync = pci_read32_sync;

}

static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
{
}

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
		struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	u8 additionlen = FCS_LEN;
	struct sk_buff *next_skb;

	/* here open is 4, wep/tkip is 8, aes is 12*/
	if (info->control.hw_key)
		additionlen += info->control.hw_key->icv_len;

	/* The most skb num is 6 */
	tcb_desc->empkt_num = 0;
	spin_lock_bh(&rtlpriv->locks.waitq_lock);
	skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
		struct ieee80211_tx_info *next_info;

		next_info = IEEE80211_SKB_CB(next_skb);
		if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
			tcb_desc->empkt_len[tcb_desc->empkt_num] =
				next_skb->len + additionlen;
			tcb_desc->empkt_num++;
		} else {
			break;
		}

		if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
				      next_skb))
			break;

		if (tcb_desc->empkt_num >= 5)
			break;
	}
	spin_unlock_bh(&rtlpriv->locks.waitq_lock);

	return true;
}

/* just for early mode now */
static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	struct sk_buff *skb = NULL;
	struct ieee80211_tx_info *info = NULL;
475
	int tid;
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511

	if (!rtlpriv->rtlhal.earlymode_enable)
		return;

	/* we juse use em for BE/BK/VI/VO */
	for (tid = 7; tid >= 0; tid--) {
		u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
		struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
		while (!mac->act_scanning &&
		       rtlpriv->psc.rfpwr_state == ERFON) {
			struct rtl_tcb_desc tcb_desc;
			memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));

			spin_lock_bh(&rtlpriv->locks.waitq_lock);
			if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
			   (ring->entries - skb_queue_len(&ring->queue) > 5)) {
				skb = skb_dequeue(&mac->skb_waitq[tid]);
			} else {
				spin_unlock_bh(&rtlpriv->locks.waitq_lock);
				break;
			}
			spin_unlock_bh(&rtlpriv->locks.waitq_lock);

			/* Some macaddr can't do early mode. like
			 * multicast/broadcast/no_qos data */
			info = IEEE80211_SKB_CB(skb);
			if (info->flags & IEEE80211_TX_CTL_AMPDU)
				_rtl_update_earlymode_info(hw, skb,
							   &tcb_desc, tid);

			rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
		}
	}
}


Larry Finger's avatar
Larry Finger committed
512
513
514
515
516
517
518
519
520
521
522
static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));

	struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];

	while (skb_queue_len(&ring->queue)) {
		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
		struct sk_buff *skb;
		struct ieee80211_tx_info *info;
523
524
		__le16 fc;
		u8 tid;
Larry Finger's avatar
Larry Finger committed
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539

		u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
							  HW_DESC_OWN);

		/*
		 *beacon packet will only use the first
		 *descriptor defautly,and the own may not
		 *be cleared by the hardware
		 */
		if (own)
			return;
		ring->idx = (ring->idx + 1) % ring->entries;

		skb = __skb_dequeue(&ring->queue);
		pci_unmap_single(rtlpci->pdev,
540
				 rtlpriv->cfg->ops->
Larry Finger's avatar
Larry Finger committed
541
					     get_desc((u8 *) entry, true,
542
						      HW_DESC_TXBUFF_ADDR),
Larry Finger's avatar
Larry Finger committed
543
544
				 skb->len, PCI_DMA_TODEVICE);

545
546
547
548
		/* remove early mode header */
		if (rtlpriv->rtlhal.earlymode_enable)
			skb_pull(skb, EM_HDR_LEN);

Larry Finger's avatar
Larry Finger committed
549
		RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE,
550
551
552
553
			 "new ring->idx:%d, free: skb_queue_len:%d, free: seq:%x\n",
			 ring->idx,
			 skb_queue_len(&ring->queue),
			 *(u16 *) (skb->data + 22));
Larry Finger's avatar
Larry Finger committed
554

555
556
557
558
559
560
561
562
563
564
565
566
		if (prio == TXCMD_QUEUE) {
			dev_kfree_skb(skb);
			goto tx_status_ok;

		}

		/* for sw LPS, just after NULL skb send out, we can
		 * sure AP kown we are sleeped, our we should not let
		 * rf to sleep*/
		fc = rtl_get_fc(skb);
		if (ieee80211_is_nullfunc(fc)) {
			if (ieee80211_has_pm(fc)) {
567
				rtlpriv->mac80211.offchan_delay = true;
568
				rtlpriv->psc.state_inap = true;
569
			} else {
570
				rtlpriv->psc.state_inap = false;
571
572
573
574
575
576
577
578
			}
		}

		/* update tid tx pkt num */
		tid = rtl_get_tid(skb);
		if (tid <= 7)
			rtlpriv->link_info.tidtx_inperiod[tid]++;

Larry Finger's avatar
Larry Finger committed
579
580
581
582
583
584
585
586
587
588
589
590
		info = IEEE80211_SKB_CB(skb);
		ieee80211_tx_info_clear_status(info);

		info->flags |= IEEE80211_TX_STAT_ACK;
		/*info->status.rates[0].count = 1; */

		ieee80211_tx_status_irqsafe(hw, skb);

		if ((ring->entries - skb_queue_len(&ring->queue))
				== 2) {

			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
591
592
593
				 "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%d\n",
				 prio, ring->idx,
				 skb_queue_len(&ring->queue));
Larry Finger's avatar
Larry Finger committed
594
595
596
597
598

			ieee80211_wake_queue(hw,
					skb_get_queue_mapping
					(skb));
		}
599
tx_status_ok:
Larry Finger's avatar
Larry Finger committed
600
601
602
603
604
605
		skb = NULL;
	}

	if (((rtlpriv->link_info.num_rx_inperiod +
		rtlpriv->link_info.num_tx_inperiod) > 8) ||
		(rtlpriv->link_info.num_rx_inperiod > 2)) {
Stanislaw Gruszka's avatar
Stanislaw Gruszka committed
606
		schedule_work(&rtlpriv->works.lps_leave_work);
Larry Finger's avatar
Larry Finger committed
607
608
609
	}
}

610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
			     struct ieee80211_rx_status rx_status)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
	__le16 fc = rtl_get_fc(skb);
	bool unicast = false;
	struct sk_buff *uskb = NULL;
	u8 *pdata;


	memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));

	if (is_broadcast_ether_addr(hdr->addr1)) {
		;/*TODO*/
	} else if (is_multicast_ether_addr(hdr->addr1)) {
		;/*TODO*/
	} else {
		unicast = true;
		rtlpriv->stats.rxbytesunicast += skb->len;
	}

	rtl_is_special_data(hw, skb, false);

	if (ieee80211_is_data(fc)) {
		rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);

		if (unicast)
			rtlpriv->link_info.num_rx_inperiod++;
	}

	/* for sw lps */
	rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
	rtl_recognize_peer(hw, (void *)skb->data, skb->len);
	if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
	    (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) &&
	     (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)))
		return;

	if (unlikely(!rtl_action_proc(hw, skb, false)))
		return;

	uskb = dev_alloc_skb(skb->len + 128);
653
654
	if (!uskb)
		return;		/* exit if allocation failed */
655
656
657
658
659
660
661
	memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status));
	pdata = (u8 *)skb_put(uskb, skb->len);
	memcpy(pdata, skb->data, skb->len);

	ieee80211_rx_irqsafe(hw, uskb);
}

Larry Finger's avatar
Larry Finger committed
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE;

	struct ieee80211_rx_status rx_status = { 0 };
	unsigned int count = rtlpci->rxringcount;
	u8 own;
	u8 tmp_one;
	u32 bufferaddress;

	struct rtl_stats stats = {
		.signal = 0,
		.noise = -98,
		.rate = 0,
	};
679
	int index = rtlpci->rx_ring[rx_queue_idx].idx;
Larry Finger's avatar
Larry Finger committed
680
681
682
683
684

	/*RX NORMAL PKT */
	while (count--) {
		/*rx descriptor */
		struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[
685
				index];
Larry Finger's avatar
Larry Finger committed
686
687
		/*rx pkt */
		struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[
688
				index];
689
		struct sk_buff *new_skb = NULL;
Larry Finger's avatar
Larry Finger committed
690
691
692
693

		own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
						       false, HW_DESC_OWN);

694
695
		/*wait data to be filled by hardware */
		if (own)
696
			break;
697

698
699
700
701
		rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
						 &rx_status,
						 (u8 *) pdesc, skb);

702
703
704
		if (stats.crc || stats.hwerror)
			goto done;

705
706
		new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
		if (unlikely(!new_skb)) {
707
708
			RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG,
				 "can't alloc skb for rx\n");
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
			goto done;
		}

		pci_unmap_single(rtlpci->pdev,
				 *((dma_addr_t *) skb->cb),
				 rtlpci->rxbuffersize,
				 PCI_DMA_FROMDEVICE);

		skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false,
			HW_DESC_RXPKT_LEN));
		skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift);

		/*
		 * NOTICE This can not be use for mac80211,
		 * this is done in mac80211 code,
		 * if you done here sec DHCP will fail
		 * skb_trim(skb, skb->len - 4);
		 */

728
		_rtl_receive_one(hw, skb, rx_status);
Larry Finger's avatar
Larry Finger committed
729

730
731
732
		if (((rtlpriv->link_info.num_rx_inperiod +
			rtlpriv->link_info.num_tx_inperiod) > 8) ||
			(rtlpriv->link_info.num_rx_inperiod > 2)) {
Stanislaw Gruszka's avatar
Stanislaw Gruszka committed
733
			schedule_work(&rtlpriv->works.lps_leave_work);
734
		}
Larry Finger's avatar
Larry Finger committed
735

736
		dev_kfree_skb_any(skb);
737
		skb = new_skb;
Larry Finger's avatar
Larry Finger committed
738

739
740
		rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb;
		*((dma_addr_t *) skb->cb) =
Larry Finger's avatar
Larry Finger committed
741
742
743
744
745
			    pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
					   rtlpci->rxbuffersize,
					   PCI_DMA_FROMDEVICE);

done:
746
		bufferaddress = (*((dma_addr_t *)skb->cb));
Larry Finger's avatar
Larry Finger committed
747
748
749
750
751
752
753
754
		tmp_one = 1;
		rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
					    HW_DESC_RXBUFF_ADDR,
					    (u8 *)&bufferaddress);
		rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
					    HW_DESC_RXPKT_LEN,
					    (u8 *)&rtlpci->rxbuffersize);

755
		if (index == rtlpci->rxringcount - 1)
Larry Finger's avatar
Larry Finger committed
756
757
758
759
			rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
						    HW_DESC_RXERO,
						    (u8 *)&tmp_one);

760
761
762
		rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
					    (u8 *)&tmp_one);

763
		index = (index + 1) % rtlpci->rxringcount;
Larry Finger's avatar
Larry Finger committed
764
765
	}

766
	rtlpci->rx_ring[rx_queue_idx].idx = index;
Larry Finger's avatar
Larry Finger committed
767
768
769
770
771
772
}

static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
{
	struct ieee80211_hw *hw = dev_id;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
773
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger's avatar
Larry Finger committed
774
775
776
	unsigned long flags;
	u32 inta = 0;
	u32 intb = 0;
777
	irqreturn_t ret = IRQ_HANDLED;
Larry Finger's avatar
Larry Finger committed
778
779
780
781
782
783
784

	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);

	/*read ISR: 4/8bytes */
	rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);

	/*Shared IRQ or HW disappared */
785
786
	if (!inta || inta == 0xffff) {
		ret = IRQ_NONE;
Larry Finger's avatar
Larry Finger committed
787
		goto done;
788
	}
Larry Finger's avatar
Larry Finger committed
789
790
791
792

	/*<1> beacon related */
	if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
793
			 "beacon ok interrupt!\n");
Larry Finger's avatar
Larry Finger committed
794
795
796
797
	}

	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) {
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
798
			 "beacon err interrupt!\n");
Larry Finger's avatar
Larry Finger committed
799
800
801
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) {
802
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n");
Larry Finger's avatar
Larry Finger committed
803
804
805
806
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
807
			 "prepare beacon for interrupt!\n");
Larry Finger's avatar
Larry Finger committed
808
809
810
811
812
		tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
	}

	/*<3> Tx related */
	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
813
		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "IMR_TXFOVW!\n");
Larry Finger's avatar
Larry Finger committed
814
815
816

	if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) {
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
817
			 "Manage ok interrupt!\n");
Larry Finger's avatar
Larry Finger committed
818
819
820
821
822
		_rtl_pci_tx_isr(hw, MGNT_QUEUE);
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) {
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
823
			 "HIGH_QUEUE ok interrupt!\n");
Larry Finger's avatar
Larry Finger committed
824
825
826
827
828
829
830
		_rtl_pci_tx_isr(hw, HIGH_QUEUE);
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_BKDOK]) {
		rtlpriv->link_info.num_tx_inperiod++;

		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
831
			 "BK Tx OK interrupt!\n");
Larry Finger's avatar
Larry Finger committed
832
833
834
835
836
837
838
		_rtl_pci_tx_isr(hw, BK_QUEUE);
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_BEDOK]) {
		rtlpriv->link_info.num_tx_inperiod++;

		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
839
			 "BE TX OK interrupt!\n");
Larry Finger's avatar
Larry Finger committed
840
841
842
843
844
845
846
		_rtl_pci_tx_isr(hw, BE_QUEUE);
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_VIDOK]) {
		rtlpriv->link_info.num_tx_inperiod++;

		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
847
			 "VI TX OK interrupt!\n");
Larry Finger's avatar
Larry Finger committed
848
849
850
851
852
853
854
		_rtl_pci_tx_isr(hw, VI_QUEUE);
	}

	if (inta & rtlpriv->cfg->maps[RTL_IMR_VODOK]) {
		rtlpriv->link_info.num_tx_inperiod++;

		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
855
			 "Vo TX OK interrupt!\n");
Larry Finger's avatar
Larry Finger committed
856
857
858
		_rtl_pci_tx_isr(hw, VO_QUEUE);
	}

859
860
861
862
863
	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
		if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) {
			rtlpriv->link_info.num_tx_inperiod++;

			RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
864
				 "CMD TX OK interrupt!\n");
865
866
867
868
			_rtl_pci_tx_isr(hw, TXCMD_QUEUE);
		}
	}

Larry Finger's avatar
Larry Finger committed
869
870
	/*<2> Rx related */
	if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
871
		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "Rx ok interrupt!\n");
872
		_rtl_pci_rx_interrupt(hw);
Larry Finger's avatar
Larry Finger committed
873
874
875
876
	}

	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
877
			 "rx descriptor unavailable!\n");
878
		_rtl_pci_rx_interrupt(hw);
Larry Finger's avatar
Larry Finger committed
879
880
881
	}

	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
882
		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "rx overflow !\n");
883
		_rtl_pci_rx_interrupt(hw);
Larry Finger's avatar
Larry Finger committed
884
885
	}

886
887
888
	if (rtlpriv->rtlhal.earlymode_enable)
		tasklet_schedule(&rtlpriv->works.irq_tasklet);

Larry Finger's avatar
Larry Finger committed
889
890
done:
	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
891
	return ret;
Larry Finger's avatar
Larry Finger committed
892
893
894
895
}

static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
{
896
	_rtl_pci_tx_chk_waitq(hw);
Larry Finger's avatar
Larry Finger committed
897
898
899
900
901
902
903
}

static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
904
	struct rtl8192_tx_ring *ring = NULL;
Larry Finger's avatar
Larry Finger committed
905
906
907
908
	struct ieee80211_hdr *hdr = NULL;
	struct ieee80211_tx_info *info = NULL;
	struct sk_buff *pskb = NULL;
	struct rtl_tx_desc *pdesc = NULL;
909
	struct rtl_tcb_desc tcb_desc;
Larry Finger's avatar
Larry Finger committed
910
911
	u8 temp_one = 1;

912
	memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
Larry Finger's avatar
Larry Finger committed
913
914
	ring = &rtlpci->tx_ring[BEACON_QUEUE];
	pskb = __skb_dequeue(&ring->queue);
915
916
917
918
919
	if (pskb) {
		struct rtl_tx_desc *entry = &ring->desc[ring->idx];
		pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc(
				 (u8 *) entry, true, HW_DESC_TXBUFF_ADDR),
				 pskb->len, PCI_DMA_TODEVICE);
Larry Finger's avatar
Larry Finger committed
920
		kfree_skb(pskb);
921
	}
Larry Finger's avatar
Larry Finger committed
922
923
924
925
926

	/*NB: the beacon data buffer must be 32-bit aligned. */
	pskb = ieee80211_beacon_get(hw, mac->vif);
	if (pskb == NULL)
		return;
927
	hdr = rtl_get_hdr(pskb);
Larry Finger's avatar
Larry Finger committed
928
929
930
	info = IEEE80211_SKB_CB(pskb);
	pdesc = &ring->desc[0];
	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
931
		info, pskb, BEACON_QUEUE, &tcb_desc);
Larry Finger's avatar
Larry Finger committed
932
933
934
935
936
937
938
939
940

	__skb_queue_tail(&ring->queue, pskb);

	rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
				    (u8 *)&temp_one);

	return;
}

Stanislaw Gruszka's avatar
Stanislaw Gruszka committed
941
942
943
944
945
946
947
948
949
static void rtl_lps_leave_work_callback(struct work_struct *work)
{
	struct rtl_works *rtlworks =
	    container_of(work, struct rtl_works, lps_leave_work);
	struct ieee80211_hw *hw = rtlworks->hw;

	rtl_lps_leave(hw);
}

Larry Finger's avatar
Larry Finger committed
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
{
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	u8 i;

	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++)
		rtlpci->txringcount[i] = RT_TXDESC_NUM;

	/*
	 *we just alloc 2 desc for beacon queue,
	 *because we just need first desc in hw beacon.
	 */
	rtlpci->txringcount[BEACON_QUEUE] = 2;

	/*
	 *BE queue need more descriptor for performance
	 *consideration or, No more tx desc will happen,
	 *and may cause mac80211 mem leakage.
	 */
	rtlpci->txringcount[BE_QUEUE] = RT_TXDESC_NUM_BE_QUEUE;

	rtlpci->rxbuffersize = 9100;	/*2048/1024; */
	rtlpci->rxringcount = RTL_PCI_MAX_RX_COUNT;	/*64; */
}

static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
		struct pci_dev *pdev)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));

	rtlpci->up_first_time = true;
	rtlpci->being_init_adapter = false;

	rtlhal->hw = hw;
	rtlpci->pdev = pdev;

	/*Tx/Rx related var */
	_rtl_pci_init_trx_var(hw);

992
	/*IBSS*/ mac->beacon_interval = 100;
Larry Finger's avatar
Larry Finger committed
993

994
995
	/*AMPDU*/
	mac->min_space_cfg = 0;
Larry Finger's avatar
Larry Finger committed
996
997
998
999
1000
	mac->max_mss_density = 0;
	/*set sane AMPDU defaults */
	mac->current_ampdu_density = 7;
	mac->current_ampdu_factor = 3;

For faster browsing, not all history is shown. View entire blame