blob: ca691550436a28faf611a91f2a7f421bdfa2da3d [file] [log] [blame]
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001/*
2 This is part of rtl818x pci OpenSource driver - v 0.1
3 Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
4 Released under the terms of GPL (General Public License)
5
6 Parts of this driver are based on the GPL part of the official
7 Realtek driver.
8
9 Parts of this driver are based on the rtl8180 driver skeleton
10 from Patric Schenke & Andres Salomon.
11
12 Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
13
14 Parts of BB/RF code are derived from David Young rtl8180 netbsd driver.
15
16 RSSI calc function from 'The Deuce'
17
18 Some ideas borrowed from the 8139too.c driver included in linux kernel.
19
20 We (I?) want to thanks the Authors of those projecs and also the
21 Ndiswrapper's project Authors.
22
23 A big big thanks goes also to Realtek corp. for their help in my attempt to
24 add RTL8185 and RTL8225 support, and to David Young also.
Bartlomiej Zolnierkiewiczb6d11c02009-06-28 16:20:10 +020025
26 Power management interface routines.
27 Written by Mariusz Matuszek.
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080028*/
29
YAMANE Toshiakife5388c2012-11-22 09:07:04 +090030#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080032#undef RX_DONT_PASS_UL
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080033#undef DUMMY_RX
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080034
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090035#include <linux/slab.h>
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080036#include <linux/syscalls.h>
Larry Finger742821c2010-02-11 12:07:35 -060037#include <linux/eeprom_93cx6.h>
Stephen Rothwell219eb472011-06-19 22:41:59 -070038#include <linux/interrupt.h>
David Howells5ba02e32013-04-08 15:48:07 +010039#include <linux/proc_fs.h>
40#include <linux/seq_file.h>
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +020041
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080042#include "r8180_hw.h"
43#include "r8180.h"
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080044#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080045#include "r8180_93cx6.h" /* Card EEPROM */
46#include "r8180_wx.h"
47#include "r8180_dm.h"
48
Bartlomiej Zolnierkiewiczfd9b8d62009-06-12 18:28:35 +020049#include "ieee80211/dot11d.h"
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080050
Bill Pemberton7df813d2012-11-19 13:24:44 -050051static struct pci_device_id rtl8180_pci_id_tbl[] = {
John Churchcb73da22010-04-08 16:04:17 -050052 {
53 .vendor = PCI_VENDOR_ID_REALTEK,
54 .device = 0x8199,
55 .subvendor = PCI_ANY_ID,
56 .subdevice = PCI_ANY_ID,
57 .driver_data = 0,
58 },
59 {
60 .vendor = 0,
61 .device = 0,
62 .subvendor = 0,
63 .subdevice = 0,
64 .driver_data = 0,
65 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080066};
67
Rusty Russelldca41302010-08-11 23:04:21 -060068static char ifname[IFNAMSIZ] = "wlan%d";
YAMANE Toshiaki49bd1362012-11-22 09:05:53 +090069static int hwwep;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080070
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080071MODULE_LICENSE("GPL");
72MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
73MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
Maxim Mikityanskiy5faca162012-11-13 19:28:13 +020074MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080075
Rusty Russelldca41302010-08-11 23:04:21 -060076module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +053077module_param(hwwep, int, S_IRUGO|S_IWUSR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080078
Prashant P. Shahbbfb5652010-05-13 23:08:43 +053079MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support. Still broken and not available on all cards");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080080
Bill Pemberton19fc6b52012-11-19 13:22:08 -050081static int rtl8180_pci_probe(struct pci_dev *pdev,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080082 const struct pci_device_id *id);
83
Bill Pembertonea7e9f22012-11-19 13:26:44 -050084static void rtl8180_pci_remove(struct pci_dev *pdev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080085
Prashant P. Shahbbfb5652010-05-13 23:08:43 +053086static void rtl8180_shutdown(struct pci_dev *pdev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080087{
88 struct net_device *dev = pci_get_drvdata(pdev);
Alexander Beregalov727ae302009-05-10 03:06:54 +040089 if (dev->netdev_ops->ndo_stop)
90 dev->netdev_ops->ndo_stop(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -080091 pci_disable_device(pdev);
92}
93
Bartlomiej Zolnierkiewiczb6d11c02009-06-28 16:20:10 +020094static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state)
95{
96 struct net_device *dev = pci_get_drvdata(pdev);
97
98 if (!netif_running(dev))
99 goto out_pci_suspend;
100
101 if (dev->netdev_ops->ndo_stop)
102 dev->netdev_ops->ndo_stop(dev);
103
104 netif_device_detach(dev);
105
106out_pci_suspend:
107 pci_save_state(pdev);
108 pci_disable_device(pdev);
109 pci_set_power_state(pdev, pci_choose_state(pdev, state));
110 return 0;
111}
112
113static int rtl8180_resume(struct pci_dev *pdev)
114{
115 struct net_device *dev = pci_get_drvdata(pdev);
116 int err;
117 u32 val;
118
119 pci_set_power_state(pdev, PCI_D0);
120
121 err = pci_enable_device(pdev);
122 if (err) {
YAMANE Toshiakife5388c2012-11-22 09:07:04 +0900123 dev_err(&pdev->dev, "pci_enable_device failed on resume\n");
Bartlomiej Zolnierkiewiczb6d11c02009-06-28 16:20:10 +0200124
125 return err;
126 }
127
128 pci_restore_state(pdev);
129
130 /*
131 * Suspend/Resume resets the PCI configuration space, so we have to
132 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
133 * from interfering with C3 CPU state. pci_restore_state won't help
134 * here since it only restores the first 64 bytes pci config header.
135 */
136 pci_read_config_dword(pdev, 0x40, &val);
137 if ((val & 0x0000ff00) != 0)
138 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
139
140 if (!netif_running(dev))
141 goto out;
142
143 if (dev->netdev_ops->ndo_open)
144 dev->netdev_ops->ndo_open(dev);
145
146 netif_device_attach(dev);
147out:
148 return 0;
149}
150
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800151static struct pci_driver rtl8180_pci_driver = {
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200152 .name = RTL8180_MODULE_NAME,
153 .id_table = rtl8180_pci_id_tbl,
154 .probe = rtl8180_pci_probe,
Bill Pemberton435c78d2012-11-19 13:20:56 -0500155 .remove = rtl8180_pci_remove,
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200156 .suspend = rtl8180_suspend,
157 .resume = rtl8180_resume,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800158 .shutdown = rtl8180_shutdown,
159};
160
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800161u8 read_nic_byte(struct net_device *dev, int x)
162{
John Churchcb73da22010-04-08 16:04:17 -0500163 return 0xff&readb((u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800164}
165
166u32 read_nic_dword(struct net_device *dev, int x)
167{
John Churchcb73da22010-04-08 16:04:17 -0500168 return readl((u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800169}
170
171u16 read_nic_word(struct net_device *dev, int x)
172{
John Churchcb73da22010-04-08 16:04:17 -0500173 return readw((u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800174}
175
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530176void write_nic_byte(struct net_device *dev, int x, u8 y)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800177{
John Churchcb73da22010-04-08 16:04:17 -0500178 writeb(y, (u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800179 udelay(20);
180}
181
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530182void write_nic_dword(struct net_device *dev, int x, u32 y)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800183{
John Churchcb73da22010-04-08 16:04:17 -0500184 writel(y, (u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800185 udelay(20);
186}
187
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530188void write_nic_word(struct net_device *dev, int x, u16 y)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800189{
John Churchcb73da22010-04-08 16:04:17 -0500190 writew(y, (u8 *)dev->mem_start + x);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800191 udelay(20);
192}
193
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800194inline void force_pci_posting(struct net_device *dev)
195{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530196 read_nic_byte(dev, EPROM_CMD);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800197 mb();
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800198}
199
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800200irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs);
201void set_nic_rxring(struct net_device *dev);
202void set_nic_txring(struct net_device *dev);
203static struct net_device_stats *rtl8180_stats(struct net_device *dev);
204void rtl8180_commit(struct net_device *dev);
205void rtl8180_start_tx_beacon(struct net_device *dev);
206
YAMANE Toshiaki49bd1362012-11-22 09:05:53 +0900207static struct proc_dir_entry *rtl8180_proc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800208
David Howells5ba02e32013-04-08 15:48:07 +0100209static int proc_get_registers(struct seq_file *m, void *v)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800210{
David Howells5ba02e32013-04-08 15:48:07 +0100211 struct net_device *dev = m->private;
212 int i, n, max = 0xff;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800213
214 /* This dump the current register page */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200215 for (n = 0; n <= max;) {
David Howells5ba02e32013-04-08 15:48:07 +0100216 seq_printf(m, "\nD: %2x > ", n);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800217
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200218 for (i = 0; i < 16 && n <= max; i++, n++)
David Howells5ba02e32013-04-08 15:48:07 +0100219 seq_printf(m, "%2x ", read_nic_byte(dev, n));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800220 }
David Howells5ba02e32013-04-08 15:48:07 +0100221 seq_putc(m, '\n');
222 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800223}
224
225int get_curr_tx_free_desc(struct net_device *dev, int priority);
226
David Howells5ba02e32013-04-08 15:48:07 +0100227static int proc_get_stats_hw(struct seq_file *m, void *v)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800228{
David Howells5ba02e32013-04-08 15:48:07 +0100229 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800230}
231
David Howells5ba02e32013-04-08 15:48:07 +0100232static int proc_get_stats_rx(struct seq_file *m, void *v)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800233{
David Howells5ba02e32013-04-08 15:48:07 +0100234 struct net_device *dev = m->private;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800235 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
236
David Howells5ba02e32013-04-08 15:48:07 +0100237 seq_printf(m,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800238 "RX OK: %lu\n"
239 "RX Retry: %lu\n"
240 "RX CRC Error(0-500): %lu\n"
241 "RX CRC Error(500-1000): %lu\n"
242 "RX CRC Error(>1000): %lu\n"
243 "RX ICV Error: %lu\n",
244 priv->stats.rxint,
245 priv->stats.rxerr,
246 priv->stats.rxcrcerrmin,
247 priv->stats.rxcrcerrmid,
248 priv->stats.rxcrcerrmax,
249 priv->stats.rxicverr
250 );
251
David Howells5ba02e32013-04-08 15:48:07 +0100252 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800253}
254
David Howells5ba02e32013-04-08 15:48:07 +0100255static int proc_get_stats_tx(struct seq_file *m, void *v)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800256{
David Howells5ba02e32013-04-08 15:48:07 +0100257 struct net_device *dev = m->private;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800258 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800259 unsigned long totalOK;
260
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530261 totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
David Howells5ba02e32013-04-08 15:48:07 +0100262 seq_printf(m,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800263 "TX OK: %lu\n"
264 "TX Error: %lu\n"
265 "TX Retry: %lu\n"
266 "TX beacon OK: %lu\n"
267 "TX beacon error: %lu\n",
268 totalOK,
269 priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr,
270 priv->stats.txretry,
271 priv->stats.txbeacon,
272 priv->stats.txbeaconerr
273 );
274
David Howells5ba02e32013-04-08 15:48:07 +0100275 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800276}
277
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800278void rtl8180_proc_module_init(void)
279{
280 DMESG("Initializing proc filesystem");
Al Viroe55d92b2011-07-24 02:07:46 -0400281 rtl8180_proc = proc_mkdir(RTL8180_MODULE_NAME, init_net.proc_net);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800282}
283
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800284void rtl8180_proc_module_remove(void)
285{
John Churchcb73da22010-04-08 16:04:17 -0500286 remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800287}
288
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800289void rtl8180_proc_remove_one(struct net_device *dev)
290{
David Howellsc4558a22013-04-12 02:59:48 +0100291 remove_proc_subtree(dev->name, rtl8180_proc);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800292}
293
David Howells5ba02e32013-04-08 15:48:07 +0100294/*
295 * seq_file wrappers for procfile show routines.
296 */
297static int rtl8180_proc_open(struct inode *inode, struct file *file)
298{
David Howells4a520d22013-04-12 14:06:01 +0100299 struct net_device *dev = proc_get_parent_data(inode);
David Howells5ba02e32013-04-08 15:48:07 +0100300 int (*show)(struct seq_file *, void *) = PDE_DATA(inode);
301
302 return single_open(file, show, dev);
303}
304
305static const struct file_operations rtl8180_proc_fops = {
306 .open = rtl8180_proc_open,
307 .read = seq_read,
308 .llseek = seq_lseek,
Al Virobae301d2013-05-05 00:15:43 -0400309 .release = single_release,
David Howells5ba02e32013-04-08 15:48:07 +0100310};
311
312/*
313 * Table of proc files we need to create.
314 */
315struct rtl8180_proc_file {
316 char name[12];
317 int (*show)(struct seq_file *, void *);
318};
319
320static const struct rtl8180_proc_file rtl8180_proc_files[] = {
321 { "stats-hw", &proc_get_stats_hw },
322 { "stats-rx", &proc_get_stats_rx },
323 { "stats-tx", &proc_get_stats_tx },
324 { "registers", &proc_get_registers },
325 { "" }
326};
327
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800328void rtl8180_proc_init_one(struct net_device *dev)
329{
David Howells5ba02e32013-04-08 15:48:07 +0100330 const struct rtl8180_proc_file *f;
David Howellsc4558a22013-04-12 02:59:48 +0100331 struct proc_dir_entry *dir;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200332
David Howellsc4558a22013-04-12 02:59:48 +0100333 dir = proc_mkdir_data(dev->name, 0, rtl8180_proc, dev);
334 if (!dir) {
335 DMESGE("Unable to initialize /proc/net/r8180/%s\n", dev->name);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800336 return;
337 }
338
David Howells5ba02e32013-04-08 15:48:07 +0100339 for (f = rtl8180_proc_files; f->name[0]; f++) {
David Howellsc4558a22013-04-12 02:59:48 +0100340 if (!proc_create_data(f->name, S_IFREG | S_IRUGO, dir,
David Howells5ba02e32013-04-08 15:48:07 +0100341 &rtl8180_proc_fops, f->show)) {
David Howellsc4558a22013-04-12 02:59:48 +0100342 DMESGE("Unable to initialize /proc/net/r8180/%s/%s\n",
343 dev->name, f->name);
David Howells5ba02e32013-04-08 15:48:07 +0100344 return;
345 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800346 }
347}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200348
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800349/*
350 FIXME: check if we can use some standard already-existent
351 data type+functions in kernel
352*/
353
354short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma,
355 struct buffer **bufferhead)
356{
John Churchcb73da22010-04-08 16:04:17 -0500357 struct buffer *tmp;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800358
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530359 if (!*buffer) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800360
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530361 *buffer = kmalloc(sizeof(struct buffer), GFP_KERNEL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800362
363 if (*buffer == NULL) {
364 DMESGE("Failed to kmalloc head of TX/RX struct");
365 return -1;
366 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530367 (*buffer)->next = *buffer;
368 (*buffer)->buf = buf;
369 (*buffer)->dma = dma;
370 if (bufferhead != NULL)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800371 (*bufferhead) = (*buffer);
372 return 0;
373 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530374 tmp = *buffer;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800375
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530376 while (tmp->next != (*buffer))
377 tmp = tmp->next;
378 tmp->next = kmalloc(sizeof(struct buffer), GFP_KERNEL);
Joe Perches53756de2010-03-24 22:17:01 -0700379 if (tmp->next == NULL) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800380 DMESGE("Failed to kmalloc TX/RX struct");
381 return -1;
382 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530383 tmp->next->buf = buf;
384 tmp->next->dma = dma;
385 tmp->next->next = *buffer;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800386
387 return 0;
388}
389
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530390void buffer_free(struct net_device *dev, struct buffer **buffer, int len, short consistent)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800391{
392
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530393 struct buffer *tmp, *next;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800394 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530395 struct pci_dev *pdev = priv->pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800396
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200397 if (!*buffer)
398 return;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800399
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200400 tmp = *buffer;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800401
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530402 do {
403 next = tmp->next;
404 if (consistent) {
405 pci_free_consistent(pdev, len,
406 tmp->buf, tmp->dma);
407 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800408 pci_unmap_single(pdev, tmp->dma,
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530409 len, PCI_DMA_FROMDEVICE);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800410 kfree(tmp->buf);
411 }
412 kfree(tmp);
413 tmp = next;
Andrew Miller24a39f72012-03-14 18:26:58 -0400414 } while (next != *buffer);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800415
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530416 *buffer = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800417}
418
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800419int get_curr_tx_free_desc(struct net_device *dev, int priority)
420{
421 struct r8180_priv *priv = ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530422 u32 *tail;
423 u32 *head;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800424 int ret;
425
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530426 switch (priority) {
427 case MANAGE_PRIORITY:
428 head = priv->txmapringhead;
429 tail = priv->txmapringtail;
430 break;
431 case BK_PRIORITY:
432 head = priv->txbkpringhead;
433 tail = priv->txbkpringtail;
434 break;
435 case BE_PRIORITY:
436 head = priv->txbepringhead;
437 tail = priv->txbepringtail;
438 break;
439 case VI_PRIORITY:
440 head = priv->txvipringhead;
441 tail = priv->txvipringtail;
442 break;
443 case VO_PRIORITY:
444 head = priv->txvopringhead;
445 tail = priv->txvopringtail;
446 break;
447 case HI_PRIORITY:
448 head = priv->txhpringhead;
449 tail = priv->txhpringtail;
450 break;
451 default:
452 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800453 }
454
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200455 if (head <= tail)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800456 ret = priv->txringcount - (tail - head)/8;
457 else
458 ret = (head - tail)/8;
459
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200460 if (ret > priv->txringcount)
461 DMESG("BUG");
462
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800463 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800464}
465
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800466short check_nic_enought_desc(struct net_device *dev, int priority)
467{
468 struct r8180_priv *priv = ieee80211_priv(dev);
469 struct ieee80211_device *ieee = netdev_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800470 int requiredbyte, required;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200471
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800472 requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
473
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200474 if (ieee->current_network.QoS_Enable)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800475 requiredbyte += 2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800476
477 required = requiredbyte / (priv->txbuffsize-4);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200478
479 if (requiredbyte % priv->txbuffsize)
480 required++;
481
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800482 /* for now we keep two free descriptor as a safety boundary
483 * between the tail and the head
484 */
485
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530486 return (required+2 < get_curr_tx_free_desc(dev, priority));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800487}
488
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800489void fix_tx_fifo(struct net_device *dev)
490{
491 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
492 u32 *tmp;
493 int i;
Bartlomiej Zolnierkiewiczff954852009-06-28 16:19:38 +0200494
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530495 for (tmp = priv->txmapring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800496 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530497 tmp += 8, i++) {
498 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800499 }
500
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530501 for (tmp = priv->txbkpring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800502 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530503 tmp += 8, i++) {
504 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800505 }
506
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530507 for (tmp = priv->txbepring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800508 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530509 tmp += 8, i++) {
510 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800511 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530512 for (tmp = priv->txvipring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800513 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530514 tmp += 8, i++) {
515 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800516 }
517
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530518 for (tmp = priv->txvopring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800519 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530520 tmp += 8, i++) {
521 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800522 }
523
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530524 for (tmp = priv->txhpring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800525 i < priv->txringcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530526 tmp += 8, i++) {
527 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800528 }
529
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530530 for (tmp = priv->txbeaconring, i = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800531 i < priv->txbeaconcount;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530532 tmp += 8, i++) {
533 *tmp = *tmp & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800534 }
Bartlomiej Zolnierkiewiczff954852009-06-28 16:19:38 +0200535
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800536 priv->txmapringtail = priv->txmapring;
537 priv->txmapringhead = priv->txmapring;
538 priv->txmapbufstail = priv->txmapbufs;
539
540 priv->txbkpringtail = priv->txbkpring;
541 priv->txbkpringhead = priv->txbkpring;
542 priv->txbkpbufstail = priv->txbkpbufs;
543
544 priv->txbepringtail = priv->txbepring;
545 priv->txbepringhead = priv->txbepring;
546 priv->txbepbufstail = priv->txbepbufs;
547
548 priv->txvipringtail = priv->txvipring;
549 priv->txvipringhead = priv->txvipring;
550 priv->txvipbufstail = priv->txvipbufs;
551
552 priv->txvopringtail = priv->txvopring;
553 priv->txvopringhead = priv->txvopring;
554 priv->txvopbufstail = priv->txvopbufs;
555
556 priv->txhpringtail = priv->txhpring;
557 priv->txhpringhead = priv->txhpring;
558 priv->txhpbufstail = priv->txhpbufs;
559
560 priv->txbeaconringtail = priv->txbeaconring;
561 priv->txbeaconbufstail = priv->txbeaconbufs;
562 set_nic_txring(dev);
563
564 ieee80211_reset_queue(priv->ieee80211);
565 priv->ack_tx_to_ieee = 0;
566}
567
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800568void fix_rx_fifo(struct net_device *dev)
569{
570 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
571 u32 *tmp;
572 struct buffer *rxbuf;
573 u8 rx_desc_size;
574
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530575 rx_desc_size = 8; /* 4*8 = 32 bytes */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800576
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530577 for (tmp = priv->rxring, rxbuf = priv->rxbufferhead;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800578 (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530579 tmp += rx_desc_size, rxbuf = rxbuf->next) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800580 *(tmp+2) = rxbuf->dma;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530581 *tmp = *tmp & ~0xfff;
582 *tmp = *tmp | priv->rxbuffersize;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800583 *tmp |= (1<<31);
584 }
585
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530586 priv->rxringtail = priv->rxring;
587 priv->rxbuffer = priv->rxbufferhead;
588 priv->rx_skb_complete = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800589 set_nic_rxring(dev);
590}
591
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800592void rtl8180_irq_disable(struct net_device *dev)
593{
594 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
595
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530596 write_nic_dword(dev, IMR, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800597 force_pci_posting(dev);
598 priv->irq_enabled = 0;
599}
600
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530601void rtl8180_set_mode(struct net_device *dev, int mode)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800602{
603 u8 ecmd;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200604
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530605 ecmd = read_nic_byte(dev, EPROM_CMD);
606 ecmd = ecmd & ~EPROM_CMD_OPERATING_MODE_MASK;
607 ecmd = ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT);
608 ecmd = ecmd & ~(1<<EPROM_CS_SHIFT);
609 ecmd = ecmd & ~(1<<EPROM_CK_SHIFT);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800610 write_nic_byte(dev, EPROM_CMD, ecmd);
611}
612
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800613void rtl8180_beacon_tx_enable(struct net_device *dev);
614
615void rtl8180_update_msr(struct net_device *dev)
616{
617 struct r8180_priv *priv = ieee80211_priv(dev);
618 u8 msr;
619 u32 rxconf;
620
621 msr = read_nic_byte(dev, MSR);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530622 msr &= ~MSR_LINK_MASK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800623
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530624 rxconf = read_nic_dword(dev, RX_CONF);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800625
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530626 if (priv->ieee80211->state == IEEE80211_LINKED) {
627 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800628 msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT);
629 else if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
630 msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT);
631 else if (priv->ieee80211->iw_mode == IW_MODE_INFRA)
632 msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT);
633 else
634 msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
635 rxconf |= (1<<RX_CHECK_BSSID_SHIFT);
636
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530637 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800638 msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
639 rxconf &= ~(1<<RX_CHECK_BSSID_SHIFT);
640 }
641
642 write_nic_byte(dev, MSR, msr);
643 write_nic_dword(dev, RX_CONF, rxconf);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800644}
645
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530646void rtl8180_set_chan(struct net_device *dev, short ch)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800647{
648 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
649
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200650 if ((ch > 14) || (ch < 1)) {
Harvey Harrisond599edc2009-01-07 14:31:57 -0800651 printk("In %s: Invalid chnanel %d\n", __func__, ch);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800652 return;
653 }
654
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530655 priv->chan = ch;
656 priv->rf_set_chan(dev, priv->chan);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800657}
658
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800659void set_nic_txring(struct net_device *dev)
660{
661 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800662
663 write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800664 write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800665 write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800666 write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800667 write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800668 write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800669 write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma);
670}
671
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800672void rtl8180_beacon_tx_enable(struct net_device *dev)
673{
674 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
675
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530676 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800677 priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530678 write_nic_byte(dev, TPPollStop, priv->dma_poll_mask);
679 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800680}
681
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800682void rtl8180_beacon_tx_disable(struct net_device *dev)
683{
684 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
685
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530686 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800687 priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530688 write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
689 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800690
691}
692
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800693void rtl8180_rtx_disable(struct net_device *dev)
694{
695 u8 cmd;
696 struct r8180_priv *priv = ieee80211_priv(dev);
697
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530698 cmd = read_nic_byte(dev, CMD);
YAMANE Toshiaki5375819d2012-11-22 09:06:37 +0900699 write_nic_byte(dev, CMD, cmd &
700 ~((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT)));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800701 force_pci_posting(dev);
702 mdelay(10);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800703
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530704 if (!priv->rx_skb_complete)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800705 dev_kfree_skb_any(priv->rx_skb);
706}
707
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800708short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
709 int addr)
710{
711 int i;
712 u32 *desc;
713 u32 *tmp;
714 dma_addr_t dma_desc, dma_tmp;
715 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
716 struct pci_dev *pdev = priv->pdev;
717 void *buf;
718
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530719 if ((bufsize & 0xfff) != bufsize) {
720 DMESGE("TX buffer allocation too large");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800721 return 0;
722 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530723 desc = (u32 *)pci_alloc_consistent(pdev,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800724 sizeof(u32)*8*count+256, &dma_desc);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200725 if (desc == NULL)
726 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800727
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200728 if (dma_desc & 0xff)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800729 /*
730 * descriptor's buffer must be 256 byte aligned
731 * we shouldn't be here, since we set DMA mask !
732 */
Larry Fingerbe286fd2009-04-18 21:09:08 -0500733 WARN(1, "DMA buffer is not aligned\n");
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200734
735 tmp = desc;
736
737 for (i = 0; i < count; i++) {
738 buf = (void *)pci_alloc_consistent(pdev, bufsize, &dma_tmp);
739 if (buf == NULL)
740 return -ENOMEM;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800741
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530742 switch (addr) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800743 case TX_MANAGEPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530744 if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800745 DMESGE("Unable to allocate mem for buffer NP");
746 return -ENOMEM;
747 }
748 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800749 case TX_BKPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530750 if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800751 DMESGE("Unable to allocate mem for buffer LP");
752 return -ENOMEM;
753 }
754 break;
755 case TX_BEPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530756 if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800757 DMESGE("Unable to allocate mem for buffer NP");
758 return -ENOMEM;
759 }
760 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800761 case TX_VIPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530762 if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800763 DMESGE("Unable to allocate mem for buffer LP");
764 return -ENOMEM;
765 }
766 break;
767 case TX_VOPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530768 if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800769 DMESGE("Unable to allocate mem for buffer NP");
770 return -ENOMEM;
771 }
772 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800773 case TX_HIGHPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530774 if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800775 DMESGE("Unable to allocate mem for buffer HP");
776 return -ENOMEM;
777 }
778 break;
779 case TX_BEACON_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530780 if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) {
781 DMESGE("Unable to allocate mem for buffer BP");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800782 return -ENOMEM;
783 }
784 break;
785 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530786 *tmp = *tmp & ~(1<<31); /* descriptor empty, owned by the drv */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800787 *(tmp+2) = (u32)dma_tmp;
788 *(tmp+3) = bufsize;
789
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530790 if (i+1 < count)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800791 *(tmp+4) = (u32)dma_desc+((i+1)*8*4);
792 else
793 *(tmp+4) = (u32)dma_desc;
794
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530795 tmp = tmp+8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800796 }
797
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530798 switch (addr) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800799 case TX_MANAGEPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530800 priv->txmapringdma = dma_desc;
801 priv->txmapring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800802 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800803 case TX_BKPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530804 priv->txbkpringdma = dma_desc;
805 priv->txbkpring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800806 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800807 case TX_BEPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530808 priv->txbepringdma = dma_desc;
809 priv->txbepring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800810 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800811 case TX_VIPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530812 priv->txvipringdma = dma_desc;
813 priv->txvipring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800814 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800815 case TX_VOPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530816 priv->txvopringdma = dma_desc;
817 priv->txvopring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800818 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800819 case TX_HIGHPRIORITY_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530820 priv->txhpringdma = dma_desc;
821 priv->txhpring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800822 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800823 case TX_BEACON_RING_ADDR:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530824 priv->txbeaconringdma = dma_desc;
825 priv->txbeaconring = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800826 break;
827
828 }
829
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800830 return 0;
831}
832
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800833void free_tx_desc_rings(struct net_device *dev)
834{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800835 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530836 struct pci_dev *pdev = priv->pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800837 int count = priv->txringcount;
838
839 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
840 priv->txmapring, priv->txmapringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530841 buffer_free(dev, &(priv->txmapbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800842
843 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
844 priv->txbkpring, priv->txbkpringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530845 buffer_free(dev, &(priv->txbkpbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800846
847 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
848 priv->txbepring, priv->txbepringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530849 buffer_free(dev, &(priv->txbepbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800850
851 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
852 priv->txvipring, priv->txvipringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530853 buffer_free(dev, &(priv->txvipbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800854
855 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
856 priv->txvopring, priv->txvopringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530857 buffer_free(dev, &(priv->txvopbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800858
859 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
860 priv->txhpring, priv->txhpringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530861 buffer_free(dev, &(priv->txhpbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800862
863 count = priv->txbeaconcount;
864 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
865 priv->txbeaconring, priv->txbeaconringdma);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530866 buffer_free(dev, &(priv->txbeaconbufs), priv->txbuffsize, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800867}
868
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800869void free_rx_desc_ring(struct net_device *dev)
870{
871 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
872 struct pci_dev *pdev = priv->pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800873 int count = priv->rxringcount;
874
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800875 pci_free_consistent(pdev, sizeof(u32)*8*count+256,
876 priv->rxring, priv->rxringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800877
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530878 buffer_free(dev, &(priv->rxbuffer), priv->rxbuffersize, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800879}
880
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800881short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
882{
883 int i;
884 u32 *desc;
885 u32 *tmp;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530886 dma_addr_t dma_desc, dma_tmp;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800887 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530888 struct pci_dev *pdev = priv->pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800889 void *buf;
890 u8 rx_desc_size;
891
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530892 rx_desc_size = 8; /* 4*8 = 32 bytes */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800893
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530894 if ((bufsize & 0xfff) != bufsize) {
895 DMESGE("RX buffer allocation too large");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800896 return -1;
897 }
898
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530899 desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800900 &dma_desc);
901
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200902 if (dma_desc & 0xff)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800903 /*
904 * descriptor's buffer must be 256 byte aligned
905 * should never happen since we specify the DMA mask
906 */
Larry Fingerbe286fd2009-04-18 21:09:08 -0500907 WARN(1, "DMA buffer is not aligned\n");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800908
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530909 priv->rxring = desc;
910 priv->rxringdma = dma_desc;
911 tmp = desc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800912
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200913 for (i = 0; i < count; i++) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530914 buf = kmalloc(bufsize * sizeof(u8), GFP_ATOMIC);
Joe Perches53756de2010-03-24 22:17:01 -0700915 if (buf == NULL) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800916 DMESGE("Failed to kmalloc RX buffer");
917 return -1;
918 }
919
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530920 dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8),
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800921 PCI_DMA_FROMDEVICE);
Larry Finger0d826c32012-12-26 20:51:13 -0600922 if (pci_dma_mapping_error(pdev, dma_tmp))
923 return -1;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530924 if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp,
925 &(priv->rxbufferhead))) {
926 DMESGE("Unable to allocate mem RX buf");
927 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800928 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530929 *tmp = 0; /* zero pads the header of the descriptor */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530930 *tmp = *tmp | (bufsize&0xfff);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800931 *(tmp+2) = (u32)dma_tmp;
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530932 *tmp = *tmp | (1<<31); /* descriptor void, owned by the NIC */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800933
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530934 tmp = tmp+rx_desc_size;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800935 }
936
Prashant P. Shah3f56c102010-05-13 23:09:08 +0530937 *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800938
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800939 return 0;
940}
941
942
943void set_nic_rxring(struct net_device *dev)
944{
945 u8 pgreg;
946 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
947
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530948 pgreg = read_nic_byte(dev, PGSELECT);
949 write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800950
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530951 write_nic_dword(dev, RXRING_ADDR, priv->rxringdma);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800952}
953
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800954void rtl8180_reset(struct net_device *dev)
955{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800956 u8 cr;
957
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800958 rtl8180_irq_disable(dev);
959
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530960 cr = read_nic_byte(dev, CMD);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800961 cr = cr & 2;
962 cr = cr | (1<<CMD_RST_SHIFT);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530963 write_nic_byte(dev, CMD, cr);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800964
965 force_pci_posting(dev);
966
967 mdelay(200);
968
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530969 if (read_nic_byte(dev, CMD) & (1<<CMD_RST_SHIFT))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800970 DMESGW("Card reset timeout!");
971 else
972 DMESG("Card successfully reset");
973
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530974 rtl8180_set_mode(dev, EPROM_CMD_LOAD);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800975 force_pci_posting(dev);
976 mdelay(200);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800977}
978
979inline u16 ieeerate2rtlrate(int rate)
980{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +0530981 switch (rate) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800982 case 10:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200983 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800984 case 20:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200985 return 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800986 case 55:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200987 return 2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800988 case 110:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200989 return 3;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800990 case 60:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200991 return 4;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800992 case 90:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200993 return 5;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800994 case 120:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200995 return 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800996 case 180:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200997 return 7;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800998 case 240:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +0200999 return 8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001000 case 360:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001001 return 9;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001002 case 480:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001003 return 10;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001004 case 540:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001005 return 11;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001006 default:
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001007 return 3;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001008 }
1009}
1010
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301011static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720};
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001012
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001013inline u16 rtl8180_rate2rate(short rate)
1014{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001015 if (rate > 12)
1016 return 10;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001017 return rtl_rate[rate];
1018}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001019
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001020inline u8 rtl8180_IsWirelessBMode(u16 rate)
1021{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301022 if (((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001023 return 1;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001024 else
1025 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001026}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001027
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001028u16 N_DBPSOfRate(u16 DataRate);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001029
1030u16 ComputeTxTime(u16 FrameLength, u16 DataRate, u8 bManagementFrame,
1031 u8 bShortPreamble)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001032{
1033 u16 FrameTime;
1034 u16 N_DBPS;
1035 u16 Ceiling;
1036
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001037 if (rtl8180_IsWirelessBMode(DataRate)) {
1038 if (bManagementFrame || !bShortPreamble || DataRate == 10)
1039 /* long preamble */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001040 FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10)));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001041 else
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001042 /* short preamble */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001043 FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10)));
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001044
1045 if ((FrameLength*8 % (DataRate/10)) != 0) /* get the ceilling */
1046 FrameTime++;
1047 } else { /* 802.11g DSSS-OFDM PLCP length field calculation. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001048 N_DBPS = N_DBPSOfRate(DataRate);
1049 Ceiling = (16 + 8*FrameLength + 6) / N_DBPS
1050 + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0);
1051 FrameTime = (u16)(16 + 4 + 4*Ceiling + 6);
1052 }
1053 return FrameTime;
1054}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001055
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001056u16 N_DBPSOfRate(u16 DataRate)
1057{
1058 u16 N_DBPS = 24;
1059
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001060 switch (DataRate) {
1061 case 60:
1062 N_DBPS = 24;
1063 break;
1064 case 90:
1065 N_DBPS = 36;
1066 break;
1067 case 120:
1068 N_DBPS = 48;
1069 break;
1070 case 180:
1071 N_DBPS = 72;
1072 break;
1073 case 240:
1074 N_DBPS = 96;
1075 break;
1076 case 360:
1077 N_DBPS = 144;
1078 break;
1079 case 480:
1080 N_DBPS = 192;
1081 break;
1082 case 540:
1083 N_DBPS = 216;
1084 break;
1085 default:
1086 break;
1087 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001088
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001089 return N_DBPS;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001090}
1091
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301092/*
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001093 * For Netgear case, they want good-looking signal strength.
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301094 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001095long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001096{
1097 long RetSS;
1098
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301099 /* Step 1. Scale mapping. */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001100 if (CurrSS >= 71 && CurrSS <= 100)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001101 RetSS = 90 + ((CurrSS - 70) / 3);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001102 else if (CurrSS >= 41 && CurrSS <= 70)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001103 RetSS = 78 + ((CurrSS - 40) / 3);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001104 else if (CurrSS >= 31 && CurrSS <= 40)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001105 RetSS = 66 + (CurrSS - 30);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001106 else if (CurrSS >= 21 && CurrSS <= 30)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001107 RetSS = 54 + (CurrSS - 20);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001108 else if (CurrSS >= 5 && CurrSS <= 20)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001109 RetSS = 42 + (((CurrSS - 5) * 2) / 3);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001110 else if (CurrSS == 4)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001111 RetSS = 36;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001112 else if (CurrSS == 3)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001113 RetSS = 27;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001114 else if (CurrSS == 2)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001115 RetSS = 18;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001116 else if (CurrSS == 1)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001117 RetSS = 9;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001118 else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001119 RetSS = CurrSS;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001120
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301121 /* Step 2. Smoothing. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301122 if (LastSS > 0)
1123 RetSS = ((LastSS * 5) + (RetSS) + 5) / 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001124
1125 return RetSS;
1126}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001127
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301128/*
1129 * Translate 0-100 signal strength index into dBm.
1130 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001131long TranslateToDbm8185(u8 SignalStrengthIndex)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001132{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001133 long SignalPower;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001134
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301135 /* Translate to dBm (x=0.5y-95). */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001136 SignalPower = (long)((SignalStrengthIndex + 1) >> 1);
1137 SignalPower -= 95;
1138
1139 return SignalPower;
1140}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001141
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301142/*
1143 * Perform signal smoothing for dynamic mechanism.
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001144 * This is different with PerformSignalSmoothing8185 in smoothing formula.
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301145 * No dramatic adjustion is apply because dynamic mechanism need some degree
1146 * of correctness. Ported from 8187B.
1147 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001148void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
1149 bool bCckRate)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001150{
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301151 /* Determin the current packet is CCK rate. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001152 priv->bCurCCKPkt = bCckRate;
1153
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001154 if (priv->UndecoratedSmoothedSS >= 0)
Andrew Millerdec3a002012-03-14 18:26:59 -04001155 priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
1156 (priv->SignalStrength * 10)) / 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001157 else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001158 priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001159
Andrew Millerdec3a002012-03-14 18:26:59 -04001160 priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) +
1161 (priv->RxPower * 11)) / 60;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001162
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001163 if (bCckRate)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001164 priv->CurCCKRSSI = priv->RSSI;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001165 else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001166 priv->CurCCKRSSI = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001167}
1168
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001169
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301170/*
1171 * This is rough RX isr handling routine
1172 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001173void rtl8180_rx(struct net_device *dev)
1174{
1175 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1176 struct sk_buff *tmp_skb;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301177 short first, last;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001178 u32 len;
1179 int lastlen;
1180 unsigned char quality, signal;
1181 u8 rate;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301182 u32 *tmp, *tmp2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001183 u8 rx_desc_size;
1184 u8 padding;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001185 char rxpower = 0;
1186 u32 RXAGC = 0;
1187 long RxAGC_dBm = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301188 u8 LNA = 0, BB = 0;
John Churchcb73da22010-04-08 16:04:17 -05001189 u8 LNA_gain[4] = {02, 17, 29, 39};
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001190 u8 Antenna = 0;
Bartlomiej Zolnierkiewicz06043842009-07-13 20:01:44 +02001191 struct ieee80211_hdr_4addr *hdr;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301192 u16 fc, type;
1193 u8 bHwError = 0, bCRC = 0, bICV = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001194 bool bCckRate = false;
1195 u8 RSSI = 0;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001196 long SignalStrengthIndex = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001197 struct ieee80211_rx_stats stats = {
1198 .signal = 0,
1199 .noise = -98,
1200 .rate = 0,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001201 .freq = IEEE80211_24GHZ_BAND,
1202 };
1203
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001204 stats.nic_type = NIC_8185B;
1205 rx_desc_size = 8;
1206
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001207 if ((*(priv->rxringtail)) & (1<<31)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001208 /* we have got an RX int, but the descriptor
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301209 * we are pointing is empty */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001210
1211 priv->stats.rxnodata++;
1212 priv->ieee80211->stats.rx_errors++;
1213
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001214 tmp2 = NULL;
1215 tmp = priv->rxringtail;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301216 do {
1217 if (tmp == priv->rxring)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001218 tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
1219 else
1220 tmp -= rx_desc_size;
1221
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301222 if (!(*tmp & (1<<31)))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001223 tmp2 = tmp;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301224 } while (tmp != priv->rxring);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001225
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301226 if (tmp2)
1227 priv->rxringtail = tmp2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001228 }
1229
1230 /* while there are filled descriptors */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301231 while (!(*(priv->rxringtail) & (1<<31))) {
1232 if (*(priv->rxringtail) & (1<<26))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001233 DMESGW("RX buffer overflow");
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301234 if (*(priv->rxringtail) & (1<<12))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001235 priv->stats.rxicverr++;
1236
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301237 if (*(priv->rxringtail) & (1<<27)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001238 priv->stats.rxdmafail++;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301239 /* DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001240 goto drop;
1241 }
1242
1243 pci_dma_sync_single_for_cpu(priv->pdev,
1244 priv->rxbuffer->dma,
YAMANE Toshiaki5375819d2012-11-22 09:06:37 +09001245 priv->rxbuffersize * sizeof(u8),
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001246 PCI_DMA_FROMDEVICE);
1247
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301248 first = *(priv->rxringtail) & (1<<29) ? 1 : 0;
1249 if (first)
1250 priv->rx_prevlen = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001251
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301252 last = *(priv->rxringtail) & (1<<28) ? 1 : 0;
1253 if (last) {
1254 lastlen = ((*priv->rxringtail) & 0xfff);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001255
1256 /* if the last descriptor (that should
1257 * tell us the total packet len) tell
1258 * us something less than the descriptors
1259 * len we had until now, then there is some
1260 * problem..
1261 * workaround to prevent kernel panic
1262 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301263 if (lastlen < priv->rx_prevlen)
1264 len = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001265 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301266 len = lastlen-priv->rx_prevlen;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001267
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301268 if (*(priv->rxringtail) & (1<<13)) {
1269 if ((*(priv->rxringtail) & 0xfff) < 500)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001270 priv->stats.rxcrcerrmin++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301271 else if ((*(priv->rxringtail) & 0x0fff) > 1000)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001272 priv->stats.rxcrcerrmax++;
1273 else
1274 priv->stats.rxcrcerrmid++;
1275
1276 }
1277
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301278 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001279 len = priv->rxbuffersize;
1280 }
1281
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301282 if (first && last) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001283 padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301284 } else if (first) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001285 padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301286 if (padding)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001287 len -= 2;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301288 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001289 padding = 0;
1290 }
John Churchcb73da22010-04-08 16:04:17 -05001291 padding = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301292 priv->rx_prevlen += len;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001293
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301294 if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001295 /* HW is probably passing several buggy frames
1296 * without FD or LD flag set.
1297 * Throw this garbage away to prevent skb
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001298 * memory exhausting
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001299 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301300 if (!priv->rx_skb_complete)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001301 dev_kfree_skb_any(priv->rx_skb);
1302 priv->rx_skb_complete = 1;
1303 }
1304
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301305 signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16);
Larry Finger19941302010-01-25 13:11:49 -06001306 signal = (signal & 0xfe) >> 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001307
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301308 quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001309
1310 stats.mac_time[0] = *(priv->rxringtail+1);
1311 stats.mac_time[1] = *(priv->rxringtail+2);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301312 rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42;
1313 RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001314
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301315 rate = ((*(priv->rxringtail)) &
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001316 ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
1317
1318 stats.rate = rtl8180_rate2rate(rate);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301319 Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301320 if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
1321 RxAGC_dBm = rxpower+1; /* bias */
1322 } else { /* CCK rate. */
1323 RxAGC_dBm = signal; /* bit 0 discard */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001324
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301325 LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */
1326 BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001327
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301328 RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001329
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301330 RxAGC_dBm += 4; /* bias */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001331 }
1332
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301333 if (RxAGC_dBm & 0x80) /* absolute value */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301334 RXAGC = ~(RxAGC_dBm)+1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001335 bCckRate = rtl8180_IsWirelessBMode(stats.rate);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301336 /* Translate RXAGC into 1-100. */
1337 if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301338 if (RXAGC > 90)
1339 RXAGC = 90;
1340 else if (RXAGC < 25)
1341 RXAGC = 25;
1342 RXAGC = (90-RXAGC)*100/65;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301343 } else { /* CCK rate. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301344 if (RXAGC > 95)
1345 RXAGC = 95;
1346 else if (RXAGC < 30)
1347 RXAGC = 30;
1348 RXAGC = (95-RXAGC)*100/65;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001349 }
1350 priv->SignalStrength = (u8)RXAGC;
Larry Finger19941302010-01-25 13:11:49 -06001351 priv->RecvSignalPower = RxAGC_dBm;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001352 priv->RxPower = rxpower;
1353 priv->RSSI = RSSI;
Larry Finger19941302010-01-25 13:11:49 -06001354 /* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301355 if (quality >= 127)
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001356 quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301357 else if (quality < 27)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001358 quality = 100;
1359 else
1360 quality = 127 - quality;
1361 priv->SignalQuality = quality;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001362
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301363 stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001364 stats.signalstrength = RXAGC;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301365 if (stats.signalstrength > 100)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001366 stats.signalstrength = 100;
1367 stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301368 /* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001369 stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301370 stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
Andrew Millerdec3a002012-03-14 18:26:59 -04001371 bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) |
1372 (((*(priv->rxringtail)) & (0x04000000)) != 0) |
1373 (((*(priv->rxringtail)) & (0x08000000)) != 0) |
1374 (((~(*(priv->rxringtail))) & (0x10000000)) != 0) |
1375 (((~(*(priv->rxringtail))) & (0x20000000)) != 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001376 bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
1377 bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
Bartlomiej Zolnierkiewicz06043842009-07-13 20:01:44 +02001378 hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001379 fc = le16_to_cpu(hdr->frame_ctl);
John Churchcb73da22010-04-08 16:04:17 -05001380 type = WLAN_FC_GET_TYPE(fc);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001381
Andrew Miller7c26d762012-03-14 10:36:51 -04001382 if (IEEE80211_FTYPE_CTL != type &&
1383 !bHwError && !bCRC && !bICV &&
1384 eqMacAddr(priv->ieee80211->current_network.bssid,
Andrew Miller24a39f72012-03-14 18:26:58 -04001385 fc & IEEE80211_FCTL_TODS ? hdr->addr1 :
1386 fc & IEEE80211_FCTL_FROMDS ? hdr->addr2 :
1387 hdr->addr3)) {
Andrew Millercd686802012-03-14 18:26:57 -04001388
Andrew Miller7c26d762012-03-14 10:36:51 -04001389 /* Perform signal smoothing for dynamic
1390 * mechanism on demand. This is different
1391 * with PerformSignalSmoothing8185 in smoothing
1392 * fomula. No dramatic adjustion is apply
1393 * because dynamic mechanism need some degree
1394 * of correctness. */
1395 PerformUndecoratedSignalSmoothing8185(priv, bCckRate);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301396
Andrew Miller7c26d762012-03-14 10:36:51 -04001397 /* For good-looking singal strength. */
1398 SignalStrengthIndex = NetgearSignalStrengthTranslate(
1399 priv->LastSignalStrengthInPercent,
1400 priv->SignalStrength);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001401
Andrew Miller7c26d762012-03-14 10:36:51 -04001402 priv->LastSignalStrengthInPercent = SignalStrengthIndex;
1403 priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301404 /*
1405 * We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
1406 * so we record the correct power here.
1407 */
Andrew Miller7c26d762012-03-14 10:36:51 -04001408 priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
1409 priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001410
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001411 /* Figure out which antenna that received the last packet. */
Andrew Miller7c26d762012-03-14 10:36:51 -04001412 priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
1413 SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
1414 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001415
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301416 if (first) {
1417 if (!priv->rx_skb_complete) {
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001418 /* seems that HW sometimes fails to receive and
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001419 doesn't provide the last descriptor */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001420 dev_kfree_skb_any(priv->rx_skb);
1421 priv->stats.rxnolast++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001422 }
Maxim Mikityanskiy861437d2012-11-13 19:28:21 +02001423 priv->rx_skb = dev_alloc_skb(len+2);
1424 if (!priv->rx_skb)
1425 goto drop;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001426
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301427 priv->rx_skb_complete = 0;
1428 priv->rx_skb->dev = dev;
1429 } else {
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001430 /* if we are here we should have already RXed
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001431 * the first frame.
1432 * If we get here and the skb is not allocated then
1433 * we have just throw out garbage (skb not allocated)
1434 * and we are still rxing garbage....
1435 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301436 if (!priv->rx_skb_complete) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001437
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301438 tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001439
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301440 if (!tmp_skb)
1441 goto drop;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001442
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301443 tmp_skb->dev = dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001444
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301445 memcpy(skb_put(tmp_skb, priv->rx_skb->len),
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001446 priv->rx_skb->data,
1447 priv->rx_skb->len);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001448
1449 dev_kfree_skb_any(priv->rx_skb);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001450
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301451 priv->rx_skb = tmp_skb;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001452 }
1453 }
Bartlomiej Zolnierkiewiczff954852009-06-28 16:19:38 +02001454
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301455 if (!priv->rx_skb_complete) {
1456 if (padding) {
1457 memcpy(skb_put(priv->rx_skb, len),
1458 (((unsigned char *)priv->rxbuffer->buf) + 2), len);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001459 } else {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301460 memcpy(skb_put(priv->rx_skb, len),
1461 priv->rxbuffer->buf, len);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001462 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001463 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001464
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301465 if (last && !priv->rx_skb_complete) {
1466 if (priv->rx_skb->len > 4)
1467 skb_trim(priv->rx_skb, priv->rx_skb->len-4);
1468 if (!ieee80211_rtl_rx(priv->ieee80211,
Larry Finger19941302010-01-25 13:11:49 -06001469 priv->rx_skb, &stats))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001470 dev_kfree_skb_any(priv->rx_skb);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301471 priv->rx_skb_complete = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001472 }
1473
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001474 pci_dma_sync_single_for_device(priv->pdev,
1475 priv->rxbuffer->dma,
YAMANE Toshiaki5375819d2012-11-22 09:06:37 +09001476 priv->rxbuffersize * sizeof(u8),
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001477 PCI_DMA_FROMDEVICE);
1478
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301479drop: /* this is used when we have not enough mem */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001480 /* restore the descriptor */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301481 *(priv->rxringtail+2) = priv->rxbuffer->dma;
1482 *(priv->rxringtail) = *(priv->rxringtail) & ~0xfff;
1483 *(priv->rxringtail) =
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001484 *(priv->rxringtail) | priv->rxbuffersize;
1485
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301486 *(priv->rxringtail) =
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001487 *(priv->rxringtail) | (1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001488
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301489 priv->rxringtail += rx_desc_size;
1490 if (priv->rxringtail >=
1491 (priv->rxring)+(priv->rxringcount)*rx_desc_size)
1492 priv->rxringtail = priv->rxring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001493
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301494 priv->rxbuffer = (priv->rxbuffer->next);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001495 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001496}
1497
1498
1499void rtl8180_dma_kick(struct net_device *dev, int priority)
1500{
1501 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1502
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301503 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001504 write_nic_byte(dev, TX_DMA_POLLING,
1505 (1 << (priority + 1)) | priv->dma_poll_mask);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301506 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001507
1508 force_pci_posting(dev);
1509}
1510
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001511void rtl8180_data_hard_stop(struct net_device *dev)
1512{
1513 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1514
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301515 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001516 priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301517 write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
1518 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001519}
1520
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001521void rtl8180_data_hard_resume(struct net_device *dev)
1522{
1523 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1524
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301525 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001526 priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301527 write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
1528 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001529}
1530
Andrew Millercd686802012-03-14 18:26:57 -04001531/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301532 * This function TX data frames when the ieee80211 stack requires this.
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001533 * It checks also if we need to stop the ieee tx queue, eventually do it
1534 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301535void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int
1536rate) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001537 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1538 int mode;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301539 struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
Larry Fingerb6b1ac62010-01-14 13:13:47 -06001540 short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001541 unsigned long flags;
1542 int priority;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001543
1544 mode = priv->ieee80211->iw_mode;
1545
1546 rate = ieeerate2rtlrate(rate);
1547 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301548 * This function doesn't require lock because we make
1549 * sure it's called with the tx_lock already acquired.
1550 * this come from the kernel's hard_xmit callback (through
1551 * the ieee stack, or from the try_wake_queue (again through
1552 * the ieee stack.
1553 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001554 priority = AC2Q(skb->priority);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301555 spin_lock_irqsave(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001556
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301557 if (priv->ieee80211->bHwRadioOff) {
1558 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001559
1560 return;
1561 }
1562
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301563 if (!check_nic_enought_desc(dev, priority)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001564 DMESGW("Error: no descriptor left by previous TX (avail %d) ",
1565 get_curr_tx_free_desc(dev, priority));
George Kadianakisdf574b82009-12-17 01:16:00 +02001566 ieee80211_rtl_stop_queue(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001567 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301568 rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001569 if (!check_nic_enought_desc(dev, priority))
George Kadianakisdf574b82009-12-17 01:16:00 +02001570 ieee80211_rtl_stop_queue(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001571
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301572 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001573}
1574
Andrew Millercd686802012-03-14 18:26:57 -04001575/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301576 * This is a rough attempt to TX a frame
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001577 * This is called by the ieee 80211 stack to TX management frames.
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001578 * If the ring is full packets are dropped (for data frame the queue
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001579 * is stopped before this can happen). For this reason it is better
1580 * if the descriptors are larger than the largest management frame
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001581 * we intend to TX: i'm unsure what the HW does if it will not find
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001582 * the last fragment of a frame because it has been dropped...
1583 * Since queues for Management and Data frames are different we
1584 * might use a different lock than tx_lock (for example mgmt_tx_lock)
1585 */
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001586/* these function may loop if invoked with 0 descriptors or 0 len buffer */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301587int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001588{
1589 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001590 unsigned long flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001591 int priority;
1592
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001593 priority = MANAGE_PRIORITY;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001594
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301595 spin_lock_irqsave(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001596
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001597 if (priv->ieee80211->bHwRadioOff) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301598 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001599 dev_kfree_skb_any(skb);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001600 return NETDEV_TX_OK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001601 }
1602
1603 rtl8180_tx(dev, skb->data, skb->len, priority,
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301604 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001605
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301606 priv->ieee80211->stats.tx_bytes += skb->len;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001607 priv->ieee80211->stats.tx_packets++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301608 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001609
1610 dev_kfree_skb_any(skb);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001611 return NETDEV_TX_OK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001612}
1613
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301614/* longpre 144+48 shortpre 72+24 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301615u16 rtl8180_len2duration(u32 len, short rate, short *ext)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001616{
1617 u16 duration;
1618 u16 drift;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301619 *ext = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001620
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301621 switch (rate) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301622 case 0: /* 1mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301623 *ext = 0;
1624 duration = ((len+4)<<4) / 0x2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001625 drift = ((len+4)<<4) % 0x2;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301626 if (drift == 0)
1627 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001628 duration++;
1629 break;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301630 case 1: /* 2mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301631 *ext = 0;
1632 duration = ((len+4)<<4) / 0x4;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001633 drift = ((len+4)<<4) % 0x4;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301634 if (drift == 0)
1635 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001636 duration++;
1637 break;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301638 case 2: /* 5.5mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301639 *ext = 0;
1640 duration = ((len+4)<<4) / 0xb;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001641 drift = ((len+4)<<4) % 0xb;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301642 if (drift == 0)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001643 break;
1644 duration++;
1645 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001646 default:
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301647 case 3: /* 11mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301648 *ext = 0;
1649 duration = ((len+4)<<4) / 0x16;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001650 drift = ((len+4)<<4) % 0x16;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301651 if (drift == 0)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001652 break;
1653 duration++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301654 if (drift > 6)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001655 break;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301656 *ext = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001657 break;
1658 }
1659
1660 return duration;
1661}
1662
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001663void rtl8180_prepare_beacon(struct net_device *dev)
1664{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001665 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001666 struct sk_buff *skb;
1667
1668 u16 word = read_nic_word(dev, BcnItv);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301669 word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
1670 word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001671 write_nic_word(dev, BcnItv, word);
1672
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001673 skb = ieee80211_get_beacon(priv->ieee80211);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301674 if (skb) {
1675 rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY,
1676 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001677 dev_kfree_skb_any(skb);
1678 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001679}
1680
Andrew Millercd686802012-03-14 18:26:57 -04001681/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301682 * This function do the real dirty work: it enqueues a TX command
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001683 * descriptor in the ring buffer, copyes the frame in a TX buffer
1684 * and kicks the NIC to ensure it does the DMA transfer.
1685 */
YAMANE Toshiakiac8bc122012-11-22 09:06:50 +09001686short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001687 short morefrag, short descfrag, int rate)
1688{
1689 struct r8180_priv *priv = ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301690 u32 *tail, *temp_tail;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001691 u32 *begin;
1692 u32 *buf;
1693 int i;
1694 int remain;
1695 int buflen;
1696 int count;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301697 struct buffer *buflist;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001698 struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
1699 u8 dest[ETH_ALEN];
1700 u8 bUseShortPreamble = 0;
1701 u8 bCTSEnable = 0;
1702 u8 bRTSEnable = 0;
John Churchcb73da22010-04-08 16:04:17 -05001703 u16 Duration = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001704 u16 RtsDur = 0;
1705 u16 ThisFrameTime = 0;
1706 u16 TxDescDuration = 0;
John Churchcb73da22010-04-08 16:04:17 -05001707 u8 ownbit_flag = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001708
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301709 switch (priority) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001710 case MANAGE_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301711 tail = priv->txmapringtail;
1712 begin = priv->txmapring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001713 buflist = priv->txmapbufstail;
1714 count = priv->txringcount;
1715 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001716 case BK_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301717 tail = priv->txbkpringtail;
1718 begin = priv->txbkpring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001719 buflist = priv->txbkpbufstail;
1720 count = priv->txringcount;
1721 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001722 case BE_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301723 tail = priv->txbepringtail;
1724 begin = priv->txbepring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001725 buflist = priv->txbepbufstail;
1726 count = priv->txringcount;
1727 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001728 case VI_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301729 tail = priv->txvipringtail;
1730 begin = priv->txvipring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001731 buflist = priv->txvipbufstail;
1732 count = priv->txringcount;
1733 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001734 case VO_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301735 tail = priv->txvopringtail;
1736 begin = priv->txvopring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001737 buflist = priv->txvopbufstail;
1738 count = priv->txringcount;
1739 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001740 case HI_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301741 tail = priv->txhpringtail;
1742 begin = priv->txhpring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001743 buflist = priv->txhpbufstail;
1744 count = priv->txringcount;
1745 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001746 case BEACON_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301747 tail = priv->txbeaconringtail;
1748 begin = priv->txbeaconring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001749 buflist = priv->txbeaconbufstail;
1750 count = priv->txbeaconcount;
1751 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001752 default:
1753 return -1;
1754 break;
John Churchcb73da22010-04-08 16:04:17 -05001755 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001756
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001757 memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
Joe Perches14fc4232012-05-08 10:11:56 -07001758 if (is_multicast_ether_addr(dest)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001759 Duration = 0;
1760 RtsDur = 0;
1761 bRTSEnable = 0;
1762 bCTSEnable = 0;
1763
Andrew Millerdec3a002012-03-14 18:26:59 -04001764 ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
1765 0, bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001766 TxDescDuration = ThisFrameTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301767 } else { /* Unicast packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001768 u16 AckTime;
1769
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301770 /* YJ,add,080828,for Keep alive */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001771 priv->NumTxUnicast++;
1772
Larry Finger19941302010-01-25 13:11:49 -06001773 /* Figure out ACK rate according to BSS basic rate
1774 * and Tx rate. */
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301775 AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001776
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301777 if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001778 u16 RtsTime, CtsTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301779 /* u16 CtsRate; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001780 bRTSEnable = 1;
1781 bCTSEnable = 0;
1782
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301783 /* Rate and time required for RTS. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301784 RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301785 /* Rate and time required for CTS. */
1786 CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001787
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301788 /* Figure out time required to transmit this frame. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001789 ThisFrameTime = ComputeTxTime(len + sCrcLng,
1790 rtl8180_rate2rate(rate),
1791 0,
1792 bUseShortPreamble);
1793
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301794 /* RTS-CTS-ThisFrame-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001795 RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
1796
1797 TxDescDuration = RtsTime + RtsDur;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301798 } else { /* Normal case. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001799 bCTSEnable = 0;
1800 bRTSEnable = 0;
1801 RtsDur = 0;
1802
Andrew Millerdec3a002012-03-14 18:26:59 -04001803 ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
1804 0, bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001805 TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
1806 }
1807
Larry Fingerb6b1ac62010-01-14 13:13:47 -06001808 if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301809 /* ThisFrame-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001810 Duration = aSifsTime + AckTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301811 } else { /* One or more fragments remained. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001812 u16 NextFragTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301813 NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001814 rtl8180_rate2rate(rate),
1815 0,
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301816 bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001817
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301818 /* ThisFrag-ACk-NextFrag-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001819 Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
1820 }
1821
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301822 } /* End of Unicast packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001823
1824 frag_hdr->duration_id = Duration;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001825
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301826 buflen = priv->txbuffsize;
1827 remain = len;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001828 temp_tail = tail;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001829
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301830 while (remain != 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001831 mb();
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301832 if (!buflist) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001833 DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001834 return -1;
1835 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301836 buf = buflist->buf;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001837
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001838 if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) {
1839 DMESGW("No more TX desc, returning %x of %x",
1840 remain, len);
1841 priv->stats.txrdu++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001842 return remain;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001843 }
1844
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301845 *tail = 0; /* zeroes header */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001846 *(tail+1) = 0;
1847 *(tail+3) = 0;
1848 *(tail+5) = 0;
1849 *(tail+6) = 0;
1850 *(tail+7) = 0;
1851
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301852 /* FIXME: this should be triggered by HW encryption parameters.*/
Larry Fingerd44eb882009-11-09 10:53:20 -06001853 *tail |= (1<<15); /* no encrypt */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001854
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301855 if (remain == len && !descfrag) {
Larry Finger19941302010-01-25 13:11:49 -06001856 ownbit_flag = false;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301857 *tail = *tail | (1<<29) ; /* fist segment of the packet */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301858 *tail = *tail | (len);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001859 } else {
1860 ownbit_flag = true;
1861 }
1862
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301863 for (i = 0; i < buflen && remain > 0; i++, remain--) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301864 ((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301865 if (remain == 4 && i+4 >= buflen)
1866 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001867 /* ensure the last desc has at least 4 bytes payload */
1868
1869 }
1870 txbuf = txbuf + i;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301871 *(tail+3) = *(tail+3) & ~0xfff;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301872 *(tail+3) = *(tail+3) | i; /* buffer length */
1873 /* Use short preamble or not */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001874 if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301875 if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
1876 ; /* *tail |= (1<<16); */ /* enable short preamble mode. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001877
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301878 if (bCTSEnable)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001879 *tail |= (1<<18);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001880
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301881 if (bRTSEnable) { /* rts enable */
1882 *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
1883 *tail |= (1<<23); /* rts enable */
1884 *(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001885 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301886 *(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
1887 /* *(tail+3) |= (0xe6<<16); */
1888 *(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001889
1890 *tail = *tail | ((rate&0xf) << 24);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001891
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301892 if (morefrag)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301893 *tail = (*tail) | (1<<17); /* more fragment */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301894 if (!remain)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301895 *tail = (*tail) | (1<<28); /* last segment of frame */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001896
John Churchcb73da22010-04-08 16:04:17 -05001897 *(tail+5) = *(tail+5)|(2<<27);
1898 *(tail+7) = *(tail+7)|(1<<4);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001899
1900 wmb();
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301901 if (ownbit_flag)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301902 *tail = *tail | (1<<31); /* descriptor ready to be txed */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001903
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301904 if ((tail - begin)/8 == count-1)
1905 tail = begin;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001906 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301907 tail = tail+8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001908
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301909 buflist = buflist->next;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001910
1911 mb();
1912
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301913 switch (priority) {
1914 case MANAGE_PRIORITY:
1915 priv->txmapringtail = tail;
1916 priv->txmapbufstail = buflist;
1917 break;
1918 case BK_PRIORITY:
1919 priv->txbkpringtail = tail;
1920 priv->txbkpbufstail = buflist;
1921 break;
1922 case BE_PRIORITY:
1923 priv->txbepringtail = tail;
1924 priv->txbepbufstail = buflist;
1925 break;
1926 case VI_PRIORITY:
1927 priv->txvipringtail = tail;
1928 priv->txvipbufstail = buflist;
1929 break;
1930 case VO_PRIORITY:
1931 priv->txvopringtail = tail;
1932 priv->txvopbufstail = buflist;
1933 break;
1934 case HI_PRIORITY:
1935 priv->txhpringtail = tail;
1936 priv->txhpbufstail = buflist;
1937 break;
1938 case BEACON_PRIORITY:
Andrew Millercd686802012-03-14 18:26:57 -04001939 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301940 * The HW seems to be happy with the 1st
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301941 * descriptor filled and the 2nd empty...
1942 * So always update descriptor 1 and never
1943 * touch 2nd
1944 */
1945 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001946 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001947 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301948 *temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301949 rtl8180_dma_kick(dev, priority);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001950
1951 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001952}
1953
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301954void rtl8180_irq_rx_tasklet(struct r8180_priv *priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001955
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001956void rtl8180_link_change(struct net_device *dev)
1957{
1958 struct r8180_priv *priv = ieee80211_priv(dev);
1959 u16 beacon_interval;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001960 struct ieee80211_network *net = &priv->ieee80211->current_network;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001961
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001962 rtl8180_update_msr(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001963
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301964 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001965
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301966 write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]);
1967 write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001968
Maxim Mikityanskiyfbce4282012-11-13 19:28:22 +02001969 beacon_interval = read_nic_word(dev, BEACON_INTERVAL);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301970 beacon_interval &= ~BEACON_INTERVAL_MASK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001971 beacon_interval |= net->beacon_interval;
Maxim Mikityanskiyfbce4282012-11-13 19:28:22 +02001972 write_nic_word(dev, BEACON_INTERVAL, beacon_interval);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001973
1974 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
1975
Larry Fingerd44eb882009-11-09 10:53:20 -06001976 rtl8180_set_chan(dev, priv->chan);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001977}
1978
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301979void rtl8180_rq_tx_ack(struct net_device *dev)
1980{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001981
1982 struct r8180_priv *priv = ieee80211_priv(dev);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001983
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301984 write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001985 priv->ack_tx_to_ieee = 1;
1986}
1987
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301988short rtl8180_is_tx_queue_empty(struct net_device *dev)
1989{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001990
1991 struct r8180_priv *priv = ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301992 u32 *d;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001993
1994 for (d = priv->txmapring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301995 d < priv->txmapring + priv->txringcount; d += 8)
1996 if (*d & (1<<31))
1997 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001998
1999 for (d = priv->txbkpring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302000 d < priv->txbkpring + priv->txringcount; d += 8)
2001 if (*d & (1<<31))
2002 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002003
2004 for (d = priv->txbepring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302005 d < priv->txbepring + priv->txringcount; d += 8)
2006 if (*d & (1<<31))
2007 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002008
2009 for (d = priv->txvipring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302010 d < priv->txvipring + priv->txringcount; d += 8)
2011 if (*d & (1<<31))
2012 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002013
2014 for (d = priv->txvopring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302015 d < priv->txvopring + priv->txringcount; d += 8)
2016 if (*d & (1<<31))
2017 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002018
2019 for (d = priv->txhpring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302020 d < priv->txhpring + priv->txringcount; d += 8)
2021 if (*d & (1<<31))
2022 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002023 return 1;
2024}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002025
2026void rtl8180_hw_wakeup(struct net_device *dev)
2027{
2028 unsigned long flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002029 struct r8180_priv *priv = ieee80211_priv(dev);
2030
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302031 spin_lock_irqsave(&priv->ps_lock, flags);
2032 write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002033 if (priv->rf_wakeup)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002034 priv->rf_wakeup(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302035 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002036}
2037
2038void rtl8180_hw_sleep_down(struct net_device *dev)
2039{
John Churchcb73da22010-04-08 16:04:17 -05002040 unsigned long flags;
2041 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002042
John Churchcb73da22010-04-08 16:04:17 -05002043 spin_lock_irqsave(&priv->ps_lock, flags);
2044 if (priv->rf_sleep)
2045 priv->rf_sleep(dev);
2046 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002047}
2048
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002049void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
2050{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002051 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002052 u32 rb = jiffies;
2053 unsigned long flags;
2054
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302055 spin_lock_irqsave(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002056
Andrew Millercd686802012-03-14 18:26:57 -04002057 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302058 * Writing HW register with 0 equals to disable
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002059 * the timer, that is not really what we want
2060 */
2061 tl -= MSECS(4+16+7);
2062
Andrew Millercd686802012-03-14 18:26:57 -04002063 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302064 * If the interval in witch we are requested to sleep is too
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002065 * short then give up and remain awake
2066 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302067 if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
2068 || ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
2069 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002070 printk("too short to sleep\n");
2071 return;
2072 }
2073
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002074 {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302075 u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002076
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002077 priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
Andrew Millerdec3a002012-03-14 18:26:59 -04002078 /* as tl may be less than rb */
2079 queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002080 }
Andrew Millercd686802012-03-14 18:26:57 -04002081 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302082 * If we suspect the TimerInt is gone beyond tl
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002083 * while setting it, then give up
2084 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002085
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302086 if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) ||
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002087 ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302088 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002089 return;
2090 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002091
2092 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302093 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002094}
2095
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302096void rtl8180_wmm_param_update(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002097{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302098 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002099 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002100 u8 *ac_param = (u8 *)(ieee->current_network.wmm_param);
2101 u8 mode = ieee->current_network.mode;
2102 AC_CODING eACI;
2103 AC_PARAM AcParam;
2104 PAC_PARAM pAcParam;
2105 u8 i;
2106
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302107 if (!ieee->current_network.QoS_Enable) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302108 /* legacy ac_xx_param update */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002109 AcParam.longData = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302110 AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002111 AcParam.f.AciAifsn.f.ACM = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302112 AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
2113 AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002114 AcParam.f.TXOPLimit = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302115 for (eACI = 0; eACI < AC_MAX; eACI++) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002116 AcParam.f.AciAifsn.f.ACI = (u8)eACI;
2117 {
2118 u8 u1bAIFS;
2119 u32 u4bAcParam;
2120 pAcParam = (PAC_PARAM)(&AcParam);
Masanari Iida3d604a32012-08-10 01:06:54 +09002121 /* Retrieve parameters to update. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302122 u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002123 u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
2124 (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
2125 (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
2126 (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302127 switch (eACI) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002128 case AC1_BK:
2129 write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
2130 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002131 case AC0_BE:
2132 write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
2133 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002134 case AC2_VI:
2135 write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
2136 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002137 case AC3_VO:
2138 write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
2139 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002140 default:
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09002141 pr_warn("SetHwReg8185():invalid ACI: %d!\n",
2142 eACI);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002143 break;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302144 }
2145 }
2146 }
2147 return;
2148 }
2149
2150 for (i = 0; i < AC_MAX; i++) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302151 /* AcParam.longData = 0; */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302152 pAcParam = (AC_PARAM *)ac_param;
2153 {
2154 AC_CODING eACI;
2155 u8 u1bAIFS;
2156 u32 u4bAcParam;
2157
Masanari Iida3d604a32012-08-10 01:06:54 +09002158 /* Retrieve parameters to update. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302159 eACI = pAcParam->f.AciAifsn.f.ACI;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302160 /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302161 u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
2162 u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
2163 (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
2164 (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
2165 (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
2166
2167 switch (eACI) {
2168 case AC1_BK:
2169 write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
2170 break;
2171 case AC0_BE:
2172 write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
2173 break;
2174 case AC2_VI:
2175 write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
2176 break;
2177 case AC3_VO:
2178 write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
2179 break;
2180 default:
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09002181 pr_warn("SetHwReg8185(): invalid ACI: %d !\n",
2182 eACI);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302183 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002184 }
2185 }
2186 ac_param += (sizeof(AC_PARAM));
2187 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002188}
2189
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002190void rtl8180_restart_wq(struct work_struct *work);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302191/* void rtl8180_rq_tx_ack(struct work_struct *work); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002192void rtl8180_watch_dog_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002193void rtl8180_hw_wakeup_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002194void rtl8180_hw_sleep_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002195void rtl8180_sw_antenna_wq(struct work_struct *work);
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02002196void rtl8180_watch_dog(struct net_device *dev);
2197
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002198void watch_dog_adaptive(unsigned long data)
2199{
YAMANE Toshiakiac8bc122012-11-22 09:06:50 +09002200 struct r8180_priv *priv = ieee80211_priv((struct net_device *)data);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002201
2202 if (!priv->up) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002203 DMESG("<----watch_dog_adaptive():driver is not up!\n");
2204 return;
2205 }
2206
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302207 /* Tx High Power Mechanism. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302208 if (CheckHighPower((struct net_device *)data))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002209 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002210
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302211 /* Tx Power Tracking on 87SE. */
Dan Carpentercffd4e12010-01-18 14:23:20 +03002212 if (CheckTxPwrTracking((struct net_device *)data))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002213 TxPwrTracking87SE((struct net_device *)data);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002214
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302215 /* Perform DIG immediately. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302216 if (CheckDig((struct net_device *)data) == true)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002217 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302218 rtl8180_watch_dog((struct net_device *)data);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002219
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002220 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
2221
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302222 priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002223 add_timer(&priv->watch_dog_timer);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002224}
2225
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002226static CHANNEL_LIST ChannelPlan[] = {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302227 {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */
2228 {{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */
2229 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */
2230 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Spain. Change to ETSI. */
2231 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* France. Change to ETSI. */
2232 {{14,36,40,44,48,52,56,60,64},9}, /* MKK */
2233 {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */
2234 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */
2235 {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */
2236 {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, /* For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 */
2237 {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} /* world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002238};
2239
2240static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
2241{
2242 int i;
2243
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302244 /* lzm add 080826 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302245 ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1;
2246 ieee->IbssStartChnl = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002247
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302248 switch (channel_plan) {
2249 case COUNTRY_CODE_FCC:
2250 case COUNTRY_CODE_IC:
2251 case COUNTRY_CODE_ETSI:
2252 case COUNTRY_CODE_SPAIN:
2253 case COUNTRY_CODE_FRANCE:
2254 case COUNTRY_CODE_MKK:
2255 case COUNTRY_CODE_MKK1:
2256 case COUNTRY_CODE_ISRAEL:
2257 case COUNTRY_CODE_TELEC:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002258 {
2259 Dot11d_Init(ieee);
2260 ieee->bGlobalDomain = false;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302261 if (ChannelPlan[channel_plan].Len != 0) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302262 /* Clear old channel map */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002263 memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302264 /* Set new channel map */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302265 for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
2266 if (ChannelPlan[channel_plan].Channel[i] <= 14)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002267 GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
2268 }
2269 }
2270 break;
2271 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302272 case COUNTRY_CODE_GLOBAL_DOMAIN:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002273 {
2274 GET_DOT11D_INFO(ieee)->bEnabled = 0;
2275 Dot11d_Reset(ieee);
2276 ieee->bGlobalDomain = true;
2277 break;
2278 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302279 case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002280 {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302281 ieee->MinPassiveChnlNum = 12;
2282 ieee->IbssStartChnl = 10;
2283 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002284 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302285 default:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002286 {
2287 Dot11d_Init(ieee);
2288 ieee->bGlobalDomain = false;
2289 memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302290 for (i = 1; i <= 14; i++)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002291 GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002292 break;
2293 }
2294 }
2295}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002296
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002297void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002298
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302299/* YJ,add,080828 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002300static void rtl8180_statistics_init(struct Stats *pstats)
2301{
2302 memset(pstats, 0, sizeof(struct Stats));
2303}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002304
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002305static void rtl8180_link_detect_init(plink_detect_t plink_detect)
2306{
2307 memset(plink_detect, 0, sizeof(link_detect_t));
2308 plink_detect->SlotNum = DEFAULT_SLOT_NUM;
2309}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002310
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302311/* YJ,add,080828,end */
Larry Finger742821c2010-02-11 12:07:35 -06002312static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
2313{
2314 struct net_device *dev = eeprom->data;
2315 u8 reg = read_nic_byte(dev, EPROM_CMD);
2316
2317 eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
2318 eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
2319 eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
2320 eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
2321}
2322
2323static void rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom)
2324{
2325 struct net_device *dev = eeprom->data;
2326 u8 reg = 2 << 6;
2327
2328 if (eeprom->reg_data_in)
2329 reg |= RTL818X_EEPROM_CMD_WRITE;
2330 if (eeprom->reg_data_out)
2331 reg |= RTL818X_EEPROM_CMD_READ;
2332 if (eeprom->reg_data_clock)
2333 reg |= RTL818X_EEPROM_CMD_CK;
2334 if (eeprom->reg_chip_select)
2335 reg |= RTL818X_EEPROM_CMD_CS;
2336
2337 write_nic_byte(dev, EPROM_CMD, reg);
2338 read_nic_byte(dev, EPROM_CMD);
2339 udelay(10);
2340}
2341
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002342short rtl8180_init(struct net_device *dev)
2343{
2344 struct r8180_priv *priv = ieee80211_priv(dev);
2345 u16 word;
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002346 u16 usValue;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002347 u16 tmpu16;
2348 int i, j;
Larry Finger742821c2010-02-11 12:07:35 -06002349 struct eeprom_93cx6 eeprom;
2350 u16 eeprom_val;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002351
Larry Finger742821c2010-02-11 12:07:35 -06002352 eeprom.data = dev;
2353 eeprom.register_read = rtl8187se_eeprom_register_read;
2354 eeprom.register_write = rtl8187se_eeprom_register_write;
2355 eeprom.width = PCI_EEPROM_WIDTH_93C46;
2356
2357 eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
2358 priv->channel_plan = eeprom_val & 0xFF;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302359 if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002360 printk("rtl8180_init:Error channel plan! Set to default.\n");
2361 priv->channel_plan = 0;
2362 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002363
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302364 DMESG("Channel plan is %d\n", priv->channel_plan);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002365 rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002366
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302367 /* FIXME: these constants are placed in a bad pleace. */
2368 priv->txbuffsize = 2048; /* 1024; */
2369 priv->txringcount = 32; /* 32; */
2370 priv->rxbuffersize = 2048; /* 1024; */
2371 priv->rxringcount = 64; /* 32; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002372 priv->txbeaconcount = 2;
2373 priv->rx_skb_complete = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002374
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002375 priv->RFChangeInProgress = false;
2376 priv->SetRFPowerStateInProgress = false;
2377 priv->RFProgType = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002378
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302379 priv->irq_enabled = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002380
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002381 rtl8180_statistics_init(&priv->stats);
2382 rtl8180_link_detect_init(&priv->link_detect);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002383
2384 priv->ack_tx_to_ieee = 0;
2385 priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
2386 priv->ieee80211->iw_mode = IW_MODE_INFRA;
2387 priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN |
2388 IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
2389 IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;
2390 priv->ieee80211->active_scan = 1;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302391 priv->ieee80211->rate = 110; /* 11 mbps */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002392 priv->ieee80211->modulation = IEEE80211_CCK_MODULATION;
2393 priv->ieee80211->host_encrypt = 1;
2394 priv->ieee80211->host_decrypt = 1;
2395 priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup;
2396 priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack;
2397 priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep;
2398 priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty;
2399
2400 priv->hw_wep = hwwep;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302401 priv->dev = dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002402 priv->retry_rts = DEFAULT_RETRY_RTS;
2403 priv->retry_data = DEFAULT_RETRY_DATA;
2404 priv->RFChangeInProgress = false;
2405 priv->SetRFPowerStateInProgress = false;
2406 priv->RFProgType = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302407 priv->bInactivePs = true; /* false; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002408 priv->ieee80211->bInactivePs = priv->bInactivePs;
2409 priv->bSwRfProcessing = false;
2410 priv->eRFPowerState = eRfOff;
2411 priv->RfOffReason = 0;
2412 priv->LedStrategy = SW_LED_MODE0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302413 priv->TxPollingTimes = 0; /* lzm add 080826 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002414 priv->bLeisurePs = true;
2415 priv->dot11PowerSaveMode = eActive;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002416 priv->AdMinCheckPeriod = 5;
2417 priv->AdMaxCheckPeriod = 10;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302418 priv->AdMaxRxSsThreshold = 30; /* 60->30 */
2419 priv->AdRxSsThreshold = 20; /* 50->20 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002420 priv->AdCheckPeriod = priv->AdMinCheckPeriod;
2421 priv->AdTickCount = 0;
2422 priv->AdRxSignalStrength = -1;
2423 priv->RegSwAntennaDiversityMechanism = 0;
2424 priv->RegDefaultAntenna = 0;
2425 priv->SignalStrength = 0;
2426 priv->AdRxOkCnt = 0;
2427 priv->CurrAntennaIndex = 0;
2428 priv->AdRxSsBeforeSwitched = 0;
2429 init_timer(&priv->SwAntennaDiversityTimer);
2430 priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
2431 priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002432 priv->bDigMechanism = 1;
2433 priv->InitialGain = 6;
2434 priv->bXtalCalibration = false;
2435 priv->XtalCal_Xin = 0;
2436 priv->XtalCal_Xout = 0;
2437 priv->bTxPowerTrack = false;
2438 priv->ThermalMeter = 0;
2439 priv->FalseAlarmRegValue = 0;
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07002440 priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002441 priv->DIG_NumberFallbackVote = 0;
2442 priv->DIG_NumberUpgradeVote = 0;
2443 priv->LastSignalStrengthInPercent = 0;
2444 priv->Stats_SignalStrength = 0;
2445 priv->LastRxPktAntenna = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302446 priv->SignalQuality = 0; /* in 0-100 index. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002447 priv->Stats_SignalQuality = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302448 priv->RecvSignalPower = 0; /* in dBm. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002449 priv->Stats_RecvSignalPower = 0;
2450 priv->AdMainAntennaRxOkCnt = 0;
2451 priv->AdAuxAntennaRxOkCnt = 0;
2452 priv->bHWAdSwitched = false;
2453 priv->bRegHighPowerMechanism = true;
2454 priv->RegHiPwrUpperTh = 77;
2455 priv->RegHiPwrLowerTh = 75;
2456 priv->RegRSSIHiPwrUpperTh = 70;
2457 priv->RegRSSIHiPwrLowerTh = 20;
2458 priv->bCurCCKPkt = false;
2459 priv->UndecoratedSmoothedSS = -1;
2460 priv->bToUpdateTxPwr = false;
2461 priv->CurCCKRSSI = 0;
2462 priv->RxPower = 0;
2463 priv->RSSI = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002464 priv->NumTxOkTotal = 0;
2465 priv->NumTxUnicast = 0;
2466 priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
Larry Finger19941302010-01-25 13:11:49 -06002467 priv->CurrRetryCnt = 0;
2468 priv->LastRetryCnt = 0;
2469 priv->LastTxokCnt = 0;
2470 priv->LastRxokCnt = 0;
2471 priv->LastRetryRate = 0;
2472 priv->bTryuping = 0;
2473 priv->CurrTxRate = 0;
2474 priv->CurrRetryRate = 0;
2475 priv->TryupingCount = 0;
2476 priv->TryupingCountNoData = 0;
2477 priv->TryDownCountLowData = 0;
2478 priv->LastTxOKBytes = 0;
2479 priv->LastFailTxRate = 0;
2480 priv->LastFailTxRateSS = 0;
2481 priv->FailTxRateCount = 0;
2482 priv->LastTxThroughput = 0;
2483 priv->NumTxOkBytesTotal = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002484 priv->ForcedDataRate = 0;
2485 priv->RegBModeGainStage = 1;
2486
Larry Finger19941302010-01-25 13:11:49 -06002487 priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002488 spin_lock_init(&priv->irq_th_lock);
2489 spin_lock_init(&priv->tx_lock);
2490 spin_lock_init(&priv->ps_lock);
2491 spin_lock_init(&priv->rf_ps_lock);
Larry Finger19941302010-01-25 13:11:49 -06002492 sema_init(&priv->wx_sem, 1);
Larry Finger19941302010-01-25 13:11:49 -06002493 INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq);
Larry Finger19941302010-01-25 13:11:49 -06002494 INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,
2495 (void *)rtl8180_hw_wakeup_wq);
2496 INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,
2497 (void *)rtl8180_hw_sleep_wq);
2498 INIT_WORK(&priv->ieee80211->wmm_param_update_wq,
2499 (void *)rtl8180_wmm_param_update);
2500 INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,
2501 (void *)rtl8180_rate_adapter);
2502 INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,
2503 (void *)rtl8180_hw_dig_wq);
2504 INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,
2505 (void *)rtl8180_tx_pw_wq);
2506 INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,
2507 (void *) GPIOChangeRFWorkItemCallBack);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002508 tasklet_init(&priv->irq_rx_tasklet,
2509 (void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
2510 (unsigned long)priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002511
Larry Finger19941302010-01-25 13:11:49 -06002512 init_timer(&priv->watch_dog_timer);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002513 priv->watch_dog_timer.data = (unsigned long)dev;
2514 priv->watch_dog_timer.function = watch_dog_adaptive;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002515
Larry Finger19941302010-01-25 13:11:49 -06002516 init_timer(&priv->rateadapter_timer);
2517 priv->rateadapter_timer.data = (unsigned long)dev;
2518 priv->rateadapter_timer.function = timer_rate_adaptive;
2519 priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
2520 priv->bEnhanceTxPwr = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002521
2522 priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit;
2523 priv->ieee80211->set_chan = rtl8180_set_chan;
2524 priv->ieee80211->link_change = rtl8180_link_change;
2525 priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit;
2526 priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop;
2527 priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume;
2528
John Churchcb73da22010-04-08 16:04:17 -05002529 priv->ieee80211->init_wmmparam_flag = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002530
2531 priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon;
2532 priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable;
2533 priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
2534
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002535 priv->ShortRetryLimit = 7;
2536 priv->LongRetryLimit = 7;
2537 priv->EarlyRxThreshold = 7;
2538
Maxim Mikityanskiy42af4992012-11-13 19:28:16 +02002539 priv->TransmitConfig = (1<<TCR_DurProcMode_OFFSET) |
Larry Finger19941302010-01-25 13:11:49 -06002540 (7<<TCR_MXDMA_OFFSET) |
2541 (priv->ShortRetryLimit<<TCR_SRL_OFFSET) |
Maxim Mikityanskiy42af4992012-11-13 19:28:16 +02002542 (priv->LongRetryLimit<<TCR_LRL_OFFSET);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002543
Larry Finger19941302010-01-25 13:11:49 -06002544 priv->ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF |
2545 RCR_AB | RCR_AM | RCR_APM |
2546 (7<<RCR_MXDMA_OFFSET) |
2547 (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) |
2548 (priv->EarlyRxThreshold == 7 ?
2549 RCR_ONLYERLPKT : 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002550
2551 priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER |
Larry Finger19941302010-01-25 13:11:49 -06002552 IMR_THPDER | IMR_THPDOK |
2553 IMR_TVODER | IMR_TVODOK |
2554 IMR_TVIDER | IMR_TVIDOK |
2555 IMR_TBEDER | IMR_TBEDOK |
2556 IMR_TBKDER | IMR_TBKDOK |
2557 IMR_RDU |
2558 IMR_RER | IMR_ROK |
2559 IMR_RQoSOK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002560
2561 priv->InitialGain = 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002562
Larry Fingerd44eb882009-11-09 10:53:20 -06002563 DMESG("MAC controller is a RTL8187SE b/g");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002564
Larry Fingerd44eb882009-11-09 10:53:20 -06002565 priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION;
2566 priv->ieee80211->short_slot = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002567
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002568 eeprom_93cx6_read(&eeprom, EEPROM_SW_REVD_OFFSET, &usValue);
2569 DMESG("usValue is %#hx\n", usValue);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302570 /* 3Read AntennaDiversity */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002571
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302572 /* SW Antenna Diversity. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002573 priv->EEPROMSwAntennaDiversity = (usValue & EEPROM_SW_AD_MASK) ==
2574 EEPROM_SW_AD_ENABLE;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002575
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302576 /* Default Antenna to use. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002577 priv->EEPROMDefaultAntenna1 = (usValue & EEPROM_DEF_ANT_MASK) ==
2578 EEPROM_DEF_ANT_1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002579
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302580 if (priv->RegSwAntennaDiversityMechanism == 0) /* Auto */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002581 /* 0: default from EEPROM. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002582 priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002583 else
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002584 /* 1:disable antenna diversity, 2: enable antenna diversity. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002585 priv->bSwAntennaDiverity = priv->RegSwAntennaDiversityMechanism == 2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002586
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002587 if (priv->RegDefaultAntenna == 0)
2588 /* 0: default from EEPROM. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002589 priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002590 else
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002591 /* 1: main, 2: aux. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002592 priv->bDefaultAntenna1 = priv->RegDefaultAntenna == 2;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002593
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002594 priv->plcp_preamble_mode = 2;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302595 /* the eeprom type is stored in RCR register bit #6 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002596 if (RCR_9356SEL & read_nic_dword(dev, RCR))
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302597 priv->epromtype = EPROM_93c56;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002598 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302599 priv->epromtype = EPROM_93c46;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002600
Larry Finger742821c2010-02-11 12:07:35 -06002601 eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)
2602 dev->dev_addr, 3);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002603
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302604 for (i = 1, j = 0; i < 14; i += 2, j++) {
Larry Finger742821c2010-02-11 12:07:35 -06002605 eeprom_93cx6_read(&eeprom, EPROM_TXPW_CH1_2 + j, &word);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302606 priv->chtxpwr[i] = word & 0xff;
2607 priv->chtxpwr[i+1] = (word & 0xff00)>>8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002608 }
Larry Fingerd44eb882009-11-09 10:53:20 -06002609 for (i = 1, j = 0; i < 14; i += 2, j++) {
Larry Finger742821c2010-02-11 12:07:35 -06002610 eeprom_93cx6_read(&eeprom, EPROM_TXPW_OFDM_CH1_2 + j, &word);
Larry Fingerd44eb882009-11-09 10:53:20 -06002611 priv->chtxpwr_ofdm[i] = word & 0xff;
Larry Finger19941302010-01-25 13:11:49 -06002612 priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002613 }
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002614
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07002615 /* 3Read crystal calibration and thermal meter indication on 87SE. */
Larry Finger742821c2010-02-11 12:07:35 -06002616 eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002617
Larry Finger19941302010-01-25 13:11:49 -06002618 /* Crystal calibration for Xin and Xout resp. */
2619 priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK;
2620 priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK) >> 4;
2621 if ((tmpu16 & EEPROM_XTAL_CAL_ENABLE) >> 12)
2622 priv->bXtalCalibration = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002623
Larry Finger19941302010-01-25 13:11:49 -06002624 /* Thermal meter reference indication. */
2625 priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK) >> 8);
2626 if ((tmpu16 & EEPROM_THERMAL_METER_ENABLE) >> 13)
2627 priv->bTxPowerTrack = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002628
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002629 priv->rf_sleep = rtl8225z4_rf_sleep;
2630 priv->rf_wakeup = rtl8225z4_rf_wakeup;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002631 DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!");
2632
2633 priv->rf_close = rtl8225z2_rf_close;
2634 priv->rf_init = rtl8225z2_rf_init;
2635 priv->rf_set_chan = rtl8225z2_rf_set_chan;
2636 priv->rf_set_sens = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002637
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302638 if (0 != alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002639 return -ENOMEM;
2640
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302641 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002642 TX_MANAGEPRIORITY_RING_ADDR))
2643 return -ENOMEM;
2644
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302645 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002646 TX_BKPRIORITY_RING_ADDR))
2647 return -ENOMEM;
2648
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302649 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002650 TX_BEPRIORITY_RING_ADDR))
2651 return -ENOMEM;
2652
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302653 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002654 TX_VIPRIORITY_RING_ADDR))
2655 return -ENOMEM;
2656
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302657 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002658 TX_VOPRIORITY_RING_ADDR))
2659 return -ENOMEM;
2660
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302661 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002662 TX_HIGHPRIORITY_RING_ADDR))
2663 return -ENOMEM;
2664
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302665 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002666 TX_BEACON_RING_ADDR))
2667 return -ENOMEM;
2668
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302669 if (request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
John Churchcb73da22010-04-08 16:04:17 -05002670 DMESGE("Error allocating IRQ %d", dev->irq);
2671 return -1;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302672 } else {
2673 priv->irq = dev->irq;
2674 DMESG("IRQ %d", dev->irq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002675 }
2676
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002677 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002678}
2679
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002680void rtl8180_no_hw_wep(struct net_device *dev)
2681{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002682}
2683
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002684void rtl8180_set_hw_wep(struct net_device *dev)
2685{
2686 struct r8180_priv *priv = ieee80211_priv(dev);
2687 u8 pgreg;
2688 u8 security;
2689 u32 key0_word4;
2690
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302691 pgreg = read_nic_byte(dev, PGSELECT);
2692 write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002693
2694 key0_word4 = read_nic_dword(dev, KEY0+4+4+4);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302695 key0_word4 &= ~0xff;
2696 key0_word4 |= priv->key0[3] & 0xff;
2697 write_nic_dword(dev, KEY0, (priv->key0[0]));
2698 write_nic_dword(dev, KEY0+4, (priv->key0[1]));
2699 write_nic_dword(dev, KEY0+4+4, (priv->key0[2]));
2700 write_nic_dword(dev, KEY0+4+4+4, (key0_word4));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002701
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302702 security = read_nic_byte(dev, SECURITY);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002703 security |= (1<<SECURITY_WEP_TX_ENABLE_SHIFT);
2704 security |= (1<<SECURITY_WEP_RX_ENABLE_SHIFT);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302705 security &= ~SECURITY_ENCRYP_MASK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002706 security |= (SECURITY_ENCRYP_104<<SECURITY_ENCRYP_SHIFT);
2707
2708 write_nic_byte(dev, SECURITY, security);
2709
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302710 DMESG("key %x %x %x %x", read_nic_dword(dev, KEY0+4+4+4),
2711 read_nic_dword(dev, KEY0+4+4), read_nic_dword(dev, KEY0+4),
2712 read_nic_dword(dev, KEY0));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002713}
2714
2715
2716void rtl8185_rf_pins_enable(struct net_device *dev)
2717{
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302718 /* u16 tmp; */
2719 /* tmp = read_nic_word(dev, RFPinsEnable); */
2720 write_nic_word(dev, RFPinsEnable, 0x1fff); /* | tmp); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002721}
2722
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002723void rtl8185_set_anaparam2(struct net_device *dev, u32 a)
2724{
2725 u8 conf3;
2726
2727 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
2728
2729 conf3 = read_nic_byte(dev, CONFIG3);
2730 write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
2731 write_nic_dword(dev, ANAPARAM2, a);
2732
2733 conf3 = read_nic_byte(dev, CONFIG3);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302734 write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002735 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002736}
2737
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002738void rtl8180_set_anaparam(struct net_device *dev, u32 a)
2739{
2740 u8 conf3;
2741
2742 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
2743
2744 conf3 = read_nic_byte(dev, CONFIG3);
2745 write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
2746 write_nic_dword(dev, ANAPARAM, a);
2747
2748 conf3 = read_nic_byte(dev, CONFIG3);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302749 write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002750 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
2751}
2752
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002753void rtl8185_tx_antenna(struct net_device *dev, u8 ant)
2754{
2755 write_nic_byte(dev, TX_ANTENNA, ant);
2756 force_pci_posting(dev);
2757 mdelay(1);
2758}
2759
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002760void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data)
2761{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002762 u32 phyw;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002763
2764 adr |= 0x80;
2765
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302766 phyw = ((data<<8) | adr);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002767
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302768 /* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002769 write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
2770 write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));
2771 write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302772 write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff)));
Bartlomiej Zolnierkiewicz5521a512009-06-28 16:19:23 +02002773
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002774 /* this is ok to fail when we write AGC table. check for AGC table might be
2775 * done by masking with 0x7f instead of 0xff
2776 */
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302777 /* if (phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002778}
2779
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302780inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002781{
2782 data = data & 0xff;
2783 rtl8185_write_phy(dev, adr, data);
2784}
2785
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302786void write_phy_cck(struct net_device *dev, u8 adr, u32 data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002787{
2788 data = data & 0xff;
2789 rtl8185_write_phy(dev, adr, data | 0x10000);
2790}
2791
Andrew Millercd686802012-03-14 18:26:57 -04002792/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302793 * This configures registers for beacon tx and enables it via
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002794 * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might
2795 * be used to stop beacon transmission
2796 */
2797void rtl8180_start_tx_beacon(struct net_device *dev)
2798{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002799 u16 word;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002800
2801 DMESG("Enabling beacon TX");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002802 rtl8180_prepare_beacon(dev);
2803 rtl8180_irq_disable(dev);
2804 rtl8180_beacon_tx_enable(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002805
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302806 word = read_nic_word(dev, AtimWnd) & ~AtimWnd_AtimWnd;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302807 write_nic_word(dev, AtimWnd, word); /* word |= */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002808
2809 word = read_nic_word(dev, BintrItv);
2810 word &= ~BintrItv_BintrItv;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302811 word |= 1000; /* priv->ieee80211->current_network.beacon_interval *
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002812 ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1);
2813 // FIXME: check if correct ^^ worked with 0x3e8;
2814 */
2815 write_nic_word(dev, BintrItv, word);
2816
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002817 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
2818
John Churchcb73da22010-04-08 16:04:17 -05002819 rtl8185b_irq_enable(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002820}
2821
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002822static struct net_device_stats *rtl8180_stats(struct net_device *dev)
2823{
2824 struct r8180_priv *priv = ieee80211_priv(dev);
2825
2826 return &priv->ieee80211->stats;
2827}
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302828
2829/*
2830 * Change current and default preamble mode.
2831 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002832bool
2833MgntActSet_802_11_PowerSaveMode(
2834 struct r8180_priv *priv,
2835 RT_PS_MODE rtPsMode
2836)
2837{
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302838 /* Currently, we do not change power save mode on IBSS mode. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302839 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002840 return false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002841
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002842 priv->ieee80211->ps = rtPsMode;
Bartlomiej Zolnierkiewicz5521a512009-06-28 16:19:23 +02002843
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002844 return true;
2845}
2846
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002847void LeisurePSEnter(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002848{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002849 if (priv->bLeisurePs) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002850 if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
Andrew Millerdec3a002012-03-14 18:26:59 -04002851 /* IEEE80211_PS_ENABLE */
2852 MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002853 }
2854}
2855
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002856void LeisurePSLeave(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002857{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002858 if (priv->bLeisurePs) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002859 if (priv->ieee80211->ps != IEEE80211_PS_DISABLED)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002860 MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002861 }
2862}
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02002863
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302864void rtl8180_hw_wakeup_wq(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002865{
Jean Delvarebf6aede2009-04-02 16:56:54 -07002866 struct delayed_work *dwork = to_delayed_work(work);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302867 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_wakeup_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002868 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002869
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002870 rtl8180_hw_wakeup(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002871}
2872
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302873void rtl8180_hw_sleep_wq(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002874{
Jean Delvarebf6aede2009-04-02 16:56:54 -07002875 struct delayed_work *dwork = to_delayed_work(work);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302876 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_sleep_wq);
John Churchcb73da22010-04-08 16:04:17 -05002877 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002878
John Churchcb73da22010-04-08 16:04:17 -05002879 rtl8180_hw_sleep_down(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002880}
2881
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302882static void MgntLinkKeepAlive(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002883{
2884 if (priv->keepAliveLevel == 0)
2885 return;
2886
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302887 if (priv->ieee80211->state == IEEE80211_LINKED) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302888 /*
2889 * Keep-Alive.
2890 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002891
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302892 if ((priv->keepAliveLevel == 2) ||
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002893 (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast &&
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302894 priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast)
2895 ) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002896 priv->link_detect.IdleCount++;
2897
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302898 /*
2899 * Send a Keep-Alive packet packet to AP if we had been idle for a while.
2900 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302901 if (priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002902 priv->link_detect.IdleCount = 0;
2903 ieee80211_sta_ps_send_null_frame(priv->ieee80211, false);
2904 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302905 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002906 priv->link_detect.IdleCount = 0;
2907 }
2908 priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast;
2909 priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast;
2910 }
2911}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002912
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002913void rtl8180_watch_dog(struct net_device *dev)
2914{
2915 struct r8180_priv *priv = ieee80211_priv(dev);
2916 bool bEnterPS = false;
2917 bool bBusyTraffic = false;
2918 u32 TotalRxNum = 0;
2919 u16 SlotIndex = 0;
2920 u16 i = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302921 if (priv->ieee80211->actscanning == false) {
Andrew Millerdec3a002012-03-14 18:26:59 -04002922 if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) &&
2923 (priv->ieee80211->state == IEEE80211_NOLINK) &&
2924 (priv->ieee80211->beinretry == false) &&
2925 (priv->eRFPowerState == eRfOn))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002926 IPSEnter(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002927 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302928 /* YJ,add,080828,for link state check */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302929 if ((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002930 SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum;
2931 priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302932 for (i = 0; i < priv->link_detect.SlotNum; i++)
2933 TotalRxNum += priv->link_detect.RxFrameNum[i];
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002934
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302935 if (TotalRxNum == 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002936 priv->ieee80211->state = IEEE80211_ASSOCIATING;
2937 queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq);
2938 }
2939 }
2940
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302941 /* YJ,add,080828,for KeepAlive */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002942 MgntLinkKeepAlive(priv);
2943
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302944 /* YJ,add,080828,for LPS */
Maxim Mikityanskiy53094af2012-11-13 19:28:23 +02002945 LeisurePSLeave(priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002946
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302947 if (priv->ieee80211->state == IEEE80211_LINKED) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002948 priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302949 if (priv->link_detect.NumRxOkInPeriod > 666 ||
2950 priv->link_detect.NumTxOkInPeriod > 666) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002951 bBusyTraffic = true;
2952 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302953 if (((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002954 || (priv->link_detect.NumRxOkInPeriod > 2)) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302955 bEnterPS = false;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002956 } else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302957 bEnterPS = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002958
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002959 if (bEnterPS)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002960 LeisurePSEnter(priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002961 else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002962 LeisurePSLeave(priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002963 } else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002964 LeisurePSLeave(priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002965 priv->link_detect.bBusyTraffic = bBusyTraffic;
2966 priv->link_detect.NumRxOkInPeriod = 0;
2967 priv->link_detect.NumTxOkInPeriod = 0;
2968 priv->ieee80211->NumRxDataInPeriod = 0;
2969 priv->ieee80211->NumRxBcnInPeriod = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002970}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002971
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002972int _rtl8180_up(struct net_device *dev)
2973{
2974 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002975
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302976 priv->up = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002977
2978 DMESG("Bringing up iface");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002979 rtl8185b_adapter_start(dev);
2980 rtl8185b_rx_enable(dev);
2981 rtl8185b_tx_enable(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302982 if (priv->bInactivePs) {
2983 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002984 IPSLeave(dev);
2985 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302986 timer_rate_adaptive((unsigned long)dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002987 watch_dog_adaptive((unsigned long)dev);
John Churchcb73da22010-04-08 16:04:17 -05002988 if (priv->bSwAntennaDiverity)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002989 SwAntennaDiversityTimerCallback(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002990 ieee80211_softmac_start_protocol(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002991 return 0;
2992}
2993
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002994int rtl8180_open(struct net_device *dev)
2995{
2996 struct r8180_priv *priv = ieee80211_priv(dev);
2997 int ret;
2998
2999 down(&priv->wx_sem);
3000 ret = rtl8180_up(dev);
3001 up(&priv->wx_sem);
3002 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003003}
3004
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003005int rtl8180_up(struct net_device *dev)
3006{
3007 struct r8180_priv *priv = ieee80211_priv(dev);
3008
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303009 if (priv->up == 1)
3010 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003011
3012 return _rtl8180_up(dev);
3013}
3014
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003015int rtl8180_close(struct net_device *dev)
3016{
3017 struct r8180_priv *priv = ieee80211_priv(dev);
3018 int ret;
3019
3020 down(&priv->wx_sem);
3021 ret = rtl8180_down(dev);
3022 up(&priv->wx_sem);
3023
3024 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003025}
3026
3027int rtl8180_down(struct net_device *dev)
3028{
3029 struct r8180_priv *priv = ieee80211_priv(dev);
3030
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003031 if (priv->up == 0)
3032 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003033
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303034 priv->up = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003035
3036 ieee80211_softmac_stop_protocol(priv->ieee80211);
3037 /* FIXME */
3038 if (!netif_queue_stopped(dev))
3039 netif_stop_queue(dev);
3040 rtl8180_rtx_disable(dev);
3041 rtl8180_irq_disable(dev);
3042 del_timer_sync(&priv->watch_dog_timer);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003043 del_timer_sync(&priv->rateadapter_timer);
3044 cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003045 cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
3046 cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
3047 cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
3048 cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
3049 del_timer_sync(&priv->SwAntennaDiversityTimer);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303050 SetZebraRFPowerState8185(dev, eRfOff);
3051 memset(&(priv->ieee80211->current_network), 0, sizeof(struct ieee80211_network));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003052 priv->ieee80211->state = IEEE80211_NOLINK;
3053 return 0;
3054}
3055
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003056void rtl8180_restart_wq(struct work_struct *work)
3057{
3058 struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
3059 struct net_device *dev = priv->dev;
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02003060
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003061 down(&priv->wx_sem);
3062
3063 rtl8180_commit(dev);
3064
3065 up(&priv->wx_sem);
3066}
3067
3068void rtl8180_restart(struct net_device *dev)
3069{
3070 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003071
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003072 schedule_work(&priv->reset_wq);
3073}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003074
3075void rtl8180_commit(struct net_device *dev)
3076{
3077 struct r8180_priv *priv = ieee80211_priv(dev);
3078
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003079 if (priv->up == 0)
3080 return ;
3081
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003082 del_timer_sync(&priv->watch_dog_timer);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003083 del_timer_sync(&priv->rateadapter_timer);
3084 cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003085 cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
3086 cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
3087 cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
3088 cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
3089 del_timer_sync(&priv->SwAntennaDiversityTimer);
3090 ieee80211_softmac_stop_protocol(priv->ieee80211);
3091 rtl8180_irq_disable(dev);
3092 rtl8180_rtx_disable(dev);
3093 _rtl8180_up(dev);
3094}
3095
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003096static void r8180_set_multicast(struct net_device *dev)
3097{
3098 struct r8180_priv *priv = ieee80211_priv(dev);
3099 short promisc;
3100
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303101 promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003102
3103 if (promisc != priv->promisc)
3104 rtl8180_restart(dev);
3105
3106 priv->promisc = promisc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003107}
3108
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003109int r8180_set_mac_adr(struct net_device *dev, void *mac)
3110{
3111 struct r8180_priv *priv = ieee80211_priv(dev);
3112 struct sockaddr *addr = mac;
3113
3114 down(&priv->wx_sem);
3115
3116 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
3117
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303118 if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003119 memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN);
3120
3121 if (priv->up) {
3122 rtl8180_down(dev);
3123 rtl8180_up(dev);
3124 }
3125
3126 up(&priv->wx_sem);
3127
3128 return 0;
3129}
3130
3131/* based on ipw2200 driver */
3132int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
3133{
3134 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003135 struct iwreq *wrq = (struct iwreq *) rq;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303136 int ret = -1;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003137
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003138 switch (cmd) {
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003139 case RTL_IOCTL_WPA_SUPPLICANT:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003140 ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data);
3141 return ret;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003142 default:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003143 return -EOPNOTSUPP;
3144 }
3145
3146 return -EOPNOTSUPP;
3147}
3148
Alexander Beregalov727ae302009-05-10 03:06:54 +04003149static const struct net_device_ops rtl8180_netdev_ops = {
3150 .ndo_open = rtl8180_open,
3151 .ndo_stop = rtl8180_close,
3152 .ndo_get_stats = rtl8180_stats,
3153 .ndo_tx_timeout = rtl8180_restart,
3154 .ndo_do_ioctl = rtl8180_ioctl,
Jiri Pirkoafc4b132011-08-16 06:29:01 +00003155 .ndo_set_rx_mode = r8180_set_multicast,
Alexander Beregalov727ae302009-05-10 03:06:54 +04003156 .ndo_set_mac_address = r8180_set_mac_adr,
3157 .ndo_validate_addr = eth_validate_addr,
3158 .ndo_change_mtu = eth_change_mtu,
George Kadianakisdf574b82009-12-17 01:16:00 +02003159 .ndo_start_xmit = ieee80211_rtl_xmit,
Alexander Beregalov727ae302009-05-10 03:06:54 +04003160};
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003161
Bill Pemberton19fc6b52012-11-19 13:22:08 -05003162static int rtl8180_pci_probe(struct pci_dev *pdev,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003163 const struct pci_device_id *id)
3164{
3165 unsigned long ioaddr = 0;
3166 struct net_device *dev = NULL;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303167 struct r8180_priv *priv = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003168 u8 unit = 0;
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003169 int ret = -ENODEV;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003170
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003171 unsigned long pmem_start, pmem_len, pmem_flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003172
3173 DMESG("Configuring chip resources");
3174
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303175 if (pci_enable_device(pdev)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003176 DMESG("Failed to enable PCI device");
3177 return -EIO;
3178 }
3179
3180 pci_set_master(pdev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003181 pci_set_dma_mask(pdev, 0xffffff00ULL);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303182 pci_set_consistent_dma_mask(pdev, 0xffffff00ULL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003183 dev = alloc_ieee80211(sizeof(struct r8180_priv));
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003184 if (!dev) {
3185 ret = -ENOMEM;
3186 goto fail_free;
3187 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003188 priv = ieee80211_priv(dev);
3189 priv->ieee80211 = netdev_priv(dev);
3190
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003191 pci_set_drvdata(pdev, dev);
3192 SET_NETDEV_DEV(dev, &pdev->dev);
3193
3194 priv = ieee80211_priv(dev);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003195 priv->pdev = pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003196
3197 pmem_start = pci_resource_start(pdev, 1);
3198 pmem_len = pci_resource_len(pdev, 1);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303199 pmem_flags = pci_resource_flags(pdev, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003200
3201 if (!(pmem_flags & IORESOURCE_MEM)) {
3202 DMESG("region #1 not a MMIO resource, aborting");
3203 goto fail;
3204 }
3205
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303206 if (!request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003207 DMESG("request_mem_region failed!");
3208 goto fail;
3209 }
3210
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303211 ioaddr = (unsigned long)ioremap_nocache(pmem_start, pmem_len);
3212 if (ioaddr == (unsigned long)NULL) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003213 DMESG("ioremap failed!");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003214 goto fail1;
3215 }
3216
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303217 dev->mem_start = ioaddr; /* shared mem start */
3218 dev->mem_end = ioaddr + pci_resource_len(pdev, 0); /* shared mem end */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003219
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003220 pci_read_config_byte(pdev, 0x05, &unit);
3221 pci_write_config_byte(pdev, 0x05, unit & (~0x04));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003222
3223 dev->irq = pdev->irq;
3224 priv->irq = 0;
3225
Alexander Beregalov727ae302009-05-10 03:06:54 +04003226 dev->netdev_ops = &rtl8180_netdev_ops;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003227 dev->wireless_handlers = &r8180_wx_handlers_def;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003228
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303229 dev->type = ARPHRD_ETHER;
Larry Finger19941302010-01-25 13:11:49 -06003230 dev->watchdog_timeo = HZ*3;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003231
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303232 if (dev_alloc_name(dev, ifname) < 0) {
John Churchcb73da22010-04-08 16:04:17 -05003233 DMESG("Oops: devname already taken! Trying wlan%%d...\n");
Rusty Russelldca41302010-08-11 23:04:21 -06003234 strcpy(ifname, "wlan%d");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003235 dev_alloc_name(dev, ifname);
John Churchcb73da22010-04-08 16:04:17 -05003236 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003237
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303238 if (rtl8180_init(dev) != 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003239 DMESG("Initialization failed");
3240 goto fail1;
3241 }
3242
3243 netif_carrier_off(dev);
3244
Kumar Amit Mehta36e97a52012-11-14 15:30:57 +05303245 if (register_netdev(dev))
3246 goto fail1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003247
3248 rtl8180_proc_init_one(dev);
3249
3250 DMESG("Driver probe completed\n");
3251 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003252fail1:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303253 if (dev->mem_start != (unsigned long)NULL) {
3254 iounmap((void *)dev->mem_start);
3255 release_mem_region(pci_resource_start(pdev, 1),
3256 pci_resource_len(pdev, 1));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003257 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003258fail:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303259 if (dev) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003260 if (priv->irq) {
3261 free_irq(dev->irq, dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303262 dev->irq = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003263 }
3264 free_ieee80211(dev);
3265 }
3266
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003267fail_free:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003268 pci_disable_device(pdev);
3269
3270 DMESG("wlan driver load failed\n");
3271 pci_set_drvdata(pdev, NULL);
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003272 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003273}
3274
Bill Pembertonea7e9f22012-11-19 13:26:44 -05003275static void rtl8180_pci_remove(struct pci_dev *pdev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003276{
3277 struct r8180_priv *priv;
3278 struct net_device *dev = pci_get_drvdata(pdev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003279
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003280 if (dev) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003281 unregister_netdev(dev);
3282
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003283 priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003284
3285 rtl8180_proc_remove_one(dev);
3286 rtl8180_down(dev);
3287 priv->rf_close(dev);
3288 rtl8180_reset(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003289 mdelay(10);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003290
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303291 if (priv->irq) {
3292 DMESG("Freeing irq %d", dev->irq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003293 free_irq(dev->irq, dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303294 priv->irq = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003295 }
3296
3297 free_rx_desc_ring(dev);
3298 free_tx_desc_rings(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003299
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303300 if (dev->mem_start != (unsigned long)NULL) {
3301 iounmap((void *)dev->mem_start);
3302 release_mem_region(pci_resource_start(pdev, 1),
3303 pci_resource_len(pdev, 1));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003304 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003305
3306 free_ieee80211(dev);
3307 }
3308 pci_disable_device(pdev);
3309
3310 DMESG("wlan driver removed\n");
3311}
3312
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003313/* fun with the built-in ieee80211 stack... */
3314extern int ieee80211_crypto_init(void);
3315extern void ieee80211_crypto_deinit(void);
3316extern int ieee80211_crypto_tkip_init(void);
3317extern void ieee80211_crypto_tkip_exit(void);
3318extern int ieee80211_crypto_ccmp_init(void);
3319extern void ieee80211_crypto_ccmp_exit(void);
3320extern int ieee80211_crypto_wep_init(void);
3321extern void ieee80211_crypto_wep_exit(void);
3322
3323static int __init rtl8180_pci_module_init(void)
3324{
3325 int ret;
3326
3327 ret = ieee80211_crypto_init();
3328 if (ret) {
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09003329 pr_err("ieee80211_crypto_init() failed %d\n", ret);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003330 return ret;
3331 }
3332 ret = ieee80211_crypto_tkip_init();
3333 if (ret) {
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09003334 pr_err("ieee80211_crypto_tkip_init() failed %d\n", ret);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003335 return ret;
3336 }
3337 ret = ieee80211_crypto_ccmp_init();
3338 if (ret) {
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09003339 pr_err("ieee80211_crypto_ccmp_init() failed %d\n", ret);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003340 return ret;
3341 }
3342 ret = ieee80211_crypto_wep_init();
3343 if (ret) {
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09003344 pr_err("ieee80211_crypto_wep_init() failed %d\n", ret);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003345 return ret;
3346 }
3347
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09003348 pr_info("\nLinux kernel driver for RTL8180 / RTL8185 based WLAN cards\n");
3349 pr_info("Copyright (c) 2004-2005, Andrea Merello\n");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003350 DMESG("Initializing module");
3351 DMESG("Wireless extensions version %d", WIRELESS_EXT);
3352 rtl8180_proc_module_init();
3353
Andrew Miller24a39f72012-03-14 18:26:58 -04003354 if (pci_register_driver(&rtl8180_pci_driver)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003355 DMESG("No device found");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003356 return -ENODEV;
3357 }
3358 return 0;
3359}
3360
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003361static void __exit rtl8180_pci_module_exit(void)
3362{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303363 pci_unregister_driver(&rtl8180_pci_driver);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003364 rtl8180_proc_module_remove();
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003365 ieee80211_crypto_tkip_exit();
3366 ieee80211_crypto_ccmp_exit();
3367 ieee80211_crypto_wep_exit();
leandro Costantino096c55d2009-02-17 11:16:26 -05003368 ieee80211_crypto_deinit();
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003369 DMESG("Exiting");
3370}
3371
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003372void rtl8180_try_wake_queue(struct net_device *dev, int pri)
3373{
3374 unsigned long flags;
3375 short enough_desc;
3376 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
3377
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303378 spin_lock_irqsave(&priv->tx_lock, flags);
3379 enough_desc = check_nic_enought_desc(dev, pri);
3380 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003381
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303382 if (enough_desc)
George Kadianakisdf574b82009-12-17 01:16:00 +02003383 ieee80211_rtl_wake_queue(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003384}
3385
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303386void rtl8180_tx_isr(struct net_device *dev, int pri, short error)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003387{
3388 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303389 u32 *tail; /* tail virtual addr */
3390 u32 *head; /* head virtual addr */
3391 u32 *begin; /* start of ring virtual addr */
3392 u32 *nicv; /* nic pointer virtual addr */
3393 u32 nic; /* nic pointer physical addr */
3394 u32 nicbegin; /* start of ring physical addr */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003395 unsigned long flag;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303396 /* physical addr are ok on 32 bits since we set DMA mask */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003397 int offs;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303398 int j, i;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003399 int hd;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303400 if (error)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303401 priv->stats.txretry++; /* tony 20060601 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303402 spin_lock_irqsave(&priv->tx_lock, flag);
3403 switch (pri) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003404 case MANAGE_PRIORITY:
3405 tail = priv->txmapringtail;
3406 begin = priv->txmapring;
3407 head = priv->txmapringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303408 nic = read_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003409 nicbegin = priv->txmapringdma;
3410 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003411 case BK_PRIORITY:
3412 tail = priv->txbkpringtail;
3413 begin = priv->txbkpring;
3414 head = priv->txbkpringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303415 nic = read_nic_dword(dev, TX_BKPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003416 nicbegin = priv->txbkpringdma;
3417 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003418 case BE_PRIORITY:
3419 tail = priv->txbepringtail;
3420 begin = priv->txbepring;
3421 head = priv->txbepringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303422 nic = read_nic_dword(dev, TX_BEPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003423 nicbegin = priv->txbepringdma;
3424 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003425 case VI_PRIORITY:
3426 tail = priv->txvipringtail;
3427 begin = priv->txvipring;
3428 head = priv->txvipringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303429 nic = read_nic_dword(dev, TX_VIPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003430 nicbegin = priv->txvipringdma;
3431 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003432 case VO_PRIORITY:
3433 tail = priv->txvopringtail;
3434 begin = priv->txvopring;
3435 head = priv->txvopringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303436 nic = read_nic_dword(dev, TX_VOPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003437 nicbegin = priv->txvopringdma;
3438 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003439 case HI_PRIORITY:
3440 tail = priv->txhpringtail;
3441 begin = priv->txhpring;
3442 head = priv->txhpringhead;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303443 nic = read_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003444 nicbegin = priv->txhpringdma;
3445 break;
3446
3447 default:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303448 spin_unlock_irqrestore(&priv->tx_lock, flag);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003449 return ;
3450 }
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003451
YAMANE Toshiakiac8bc122012-11-22 09:06:50 +09003452 nicv = (u32 *)((nic - nicbegin) + (u8 *)begin);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303453 if ((head <= tail && (nicv > tail || nicv < head)) ||
3454 (head > tail && (nicv > tail && nicv < head))) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003455 DMESGW("nic has lost pointer");
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303456 spin_unlock_irqrestore(&priv->tx_lock, flag);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003457 rtl8180_restart(dev);
3458 return;
3459 }
3460
Andrew Millercd686802012-03-14 18:26:57 -04003461 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303462 * We check all the descriptors between the head and the nic,
André Goddard Rosabbc9a992009-11-14 13:09:06 -02003463 * but not the currently pointed by the nic (the next to be txed)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003464 * and the previous of the pointed (might be in process ??)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303465 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003466 offs = (nic - nicbegin);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303467 offs = offs / 8 / 4;
3468 hd = (head - begin) / 8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003469
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303470 if (offs >= hd)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003471 j = offs - hd;
3472 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303473 j = offs + (priv->txringcount-1-hd);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003474
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303475 j -= 2;
3476 if (j < 0)
3477 j = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003478
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303479 for (i = 0; i < j; i++) {
3480 if ((*head) & (1<<31))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003481 break;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303482 if (((*head)&(0x10000000)) != 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003483 priv->CurrRetryCnt += (u16)((*head) & (0x000000ff));
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003484 if (!error)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003485 priv->NumTxOkTotal++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003486 }
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003487
3488 if (!error)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003489 priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003490
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303491 *head = *head & ~(1<<31);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003492
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303493 if ((head - begin)/8 == priv->txringcount-1)
3494 head = begin;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003495 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303496 head += 8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003497 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003498
Andrew Millercd686802012-03-14 18:26:57 -04003499 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303500 * The head has been moved to the last certainly TXed
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003501 * (or at least processed by the nic) packet.
3502 * The driver take forcefully owning of all these packets
3503 * If the packet previous of the nic pointer has been
3504 * processed this doesn't matter: it will be checked
3505 * here at the next round. Anyway if no more packet are
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003506 * TXed no memory leak occur at all.
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003507 */
3508
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303509 switch (pri) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003510 case MANAGE_PRIORITY:
3511 priv->txmapringhead = head;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003512
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303513 if (priv->ack_tx_to_ieee) {
3514 if (rtl8180_is_tx_queue_empty(dev)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003515 priv->ack_tx_to_ieee = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303516 ieee80211_ps_tx_ack(priv->ieee80211, !error);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003517 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003518 }
3519 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003520 case BK_PRIORITY:
3521 priv->txbkpringhead = head;
3522 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003523 case BE_PRIORITY:
3524 priv->txbepringhead = head;
3525 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003526 case VI_PRIORITY:
3527 priv->txvipringhead = head;
3528 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003529 case VO_PRIORITY:
3530 priv->txvopringhead = head;
3531 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003532 case HI_PRIORITY:
3533 priv->txhpringhead = head;
3534 break;
3535 }
3536
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303537 spin_unlock_irqrestore(&priv->tx_lock, flag);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003538}
3539
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003540irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
3541{
3542 struct net_device *dev = (struct net_device *) netdev;
3543 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
3544 unsigned long flags;
3545 u32 inta;
3546
3547 /* We should return IRQ_NONE, but for now let me keep this */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303548 if (priv->irq_enabled == 0)
3549 return IRQ_HANDLED;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003550
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303551 spin_lock_irqsave(&priv->irq_th_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003552
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303553 /* ISR: 4bytes */
3554 inta = read_nic_dword(dev, ISR); /* & priv->IntrMask; */
3555 write_nic_dword(dev, ISR, inta); /* reset int situation */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003556
3557 priv->stats.shints++;
3558
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303559 if (!inta) {
3560 spin_unlock_irqrestore(&priv->irq_th_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003561 return IRQ_HANDLED;
3562 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303563 * most probably we can safely return IRQ_NONE,
3564 * but for now is better to avoid problems
3565 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003566 }
3567
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003568 if (inta == 0xffff) {
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07003569 /* HW disappeared */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003570 spin_unlock_irqrestore(&priv->irq_th_lock, flags);
3571 return IRQ_HANDLED;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003572 }
3573
3574 priv->stats.ints++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003575
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303576 if (!netif_running(dev)) {
3577 spin_unlock_irqrestore(&priv->irq_th_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003578 return IRQ_HANDLED;
3579 }
3580
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003581 if (inta & ISR_TimeOut)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003582 write_nic_dword(dev, TimerInt, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003583
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003584 if (inta & ISR_TBDOK)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003585 priv->stats.txbeacon++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003586
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003587 if (inta & ISR_TBDER)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003588 priv->stats.txbeaconerr++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003589
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003590 if (inta & IMR_TMGDOK)
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303591 rtl8180_tx_isr(dev, MANAGE_PRIORITY, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003592
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303593 if (inta & ISR_THPDER) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003594 priv->stats.txhperr++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303595 rtl8180_tx_isr(dev, HI_PRIORITY, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003596 priv->ieee80211->stats.tx_errors++;
3597 }
3598
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303599 if (inta & ISR_THPDOK) { /* High priority tx ok */
3600 priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003601 priv->stats.txhpokint++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303602 rtl8180_tx_isr(dev, HI_PRIORITY, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003603 }
3604
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303605 if (inta & ISR_RER)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003606 priv->stats.rxerr++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303607
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303608 if (inta & ISR_TBKDER) { /* corresponding to BK_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003609 priv->stats.txbkperr++;
3610 priv->ieee80211->stats.tx_errors++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303611 rtl8180_tx_isr(dev, BK_PRIORITY, 1);
Maxim Mikityanskiyddedb782012-11-13 19:28:10 +02003612 rtl8180_try_wake_queue(dev, BK_PRIORITY);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003613 }
3614
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303615 if (inta & ISR_TBEDER) { /* corresponding to BE_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003616 priv->stats.txbeperr++;
3617 priv->ieee80211->stats.tx_errors++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303618 rtl8180_tx_isr(dev, BE_PRIORITY, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003619 rtl8180_try_wake_queue(dev, BE_PRIORITY);
3620 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303621 if (inta & ISR_TNPDER) { /* corresponding to VO_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003622 priv->stats.txnperr++;
3623 priv->ieee80211->stats.tx_errors++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303624 rtl8180_tx_isr(dev, NORM_PRIORITY, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003625 rtl8180_try_wake_queue(dev, NORM_PRIORITY);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003626 }
3627
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303628 if (inta & ISR_TLPDER) { /* corresponding to VI_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003629 priv->stats.txlperr++;
3630 priv->ieee80211->stats.tx_errors++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303631 rtl8180_tx_isr(dev, LOW_PRIORITY, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003632 rtl8180_try_wake_queue(dev, LOW_PRIORITY);
3633 }
3634
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303635 if (inta & ISR_ROK) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003636 priv->stats.rxint++;
3637 tasklet_schedule(&priv->irq_rx_tasklet);
3638 }
3639
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303640 if (inta & ISR_RQoSOK) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003641 priv->stats.rxint++;
3642 tasklet_schedule(&priv->irq_rx_tasklet);
3643 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303644
3645 if (inta & ISR_BcnInt)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003646 rtl8180_prepare_beacon(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003647
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303648 if (inta & ISR_RDU) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003649 DMESGW("No RX descriptor available");
3650 priv->stats.rxrdu++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003651 tasklet_schedule(&priv->irq_rx_tasklet);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003652 }
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003653
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303654 if (inta & ISR_RXFOVW) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003655 priv->stats.rxoverflow++;
3656 tasklet_schedule(&priv->irq_rx_tasklet);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003657 }
3658
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003659 if (inta & ISR_TXFOVW)
3660 priv->stats.txoverflow++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003661
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303662 if (inta & ISR_TNPDOK) { /* Normal priority tx ok */
3663 priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003664 priv->stats.txnpokint++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303665 rtl8180_tx_isr(dev, NORM_PRIORITY, 0);
Maxim Mikityanskiyddedb782012-11-13 19:28:10 +02003666 rtl8180_try_wake_queue(dev, NORM_PRIORITY);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003667 }
3668
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303669 if (inta & ISR_TLPDOK) { /* Low priority tx ok */
3670 priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003671 priv->stats.txlpokint++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303672 rtl8180_tx_isr(dev, LOW_PRIORITY, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003673 rtl8180_try_wake_queue(dev, LOW_PRIORITY);
3674 }
3675
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303676 if (inta & ISR_TBKDOK) { /* corresponding to BK_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003677 priv->stats.txbkpokint++;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303678 priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303679 rtl8180_tx_isr(dev, BK_PRIORITY, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003680 rtl8180_try_wake_queue(dev, BE_PRIORITY);
3681 }
3682
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303683 if (inta & ISR_TBEDOK) { /* corresponding to BE_PRIORITY */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003684 priv->stats.txbeperr++;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303685 priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303686 rtl8180_tx_isr(dev, BE_PRIORITY, 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003687 rtl8180_try_wake_queue(dev, BE_PRIORITY);
3688 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003689 force_pci_posting(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303690 spin_unlock_irqrestore(&priv->irq_th_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003691
3692 return IRQ_HANDLED;
3693}
3694
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303695void rtl8180_irq_rx_tasklet(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003696{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003697 rtl8180_rx(priv->dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003698}
3699
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003700void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
3701{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003702 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
3703 struct net_device *dev = ieee->dev;
3704 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003705 u8 btPSR;
3706 u8 btConfig0;
3707 RT_RF_POWER_STATE eRfPowerStateToSet;
John Churchcb73da22010-04-08 16:04:17 -05003708 bool bActuallySet = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003709
3710 char *argv[3];
John Churchcb73da22010-04-08 16:04:17 -05003711 static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh";
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303712 static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL};
YAMANE Toshiaki49bd1362012-11-22 09:05:53 +09003713 static int readf_count;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003714
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003715 readf_count = (readf_count+1)%0xffff;
Larry Finger19941302010-01-25 13:11:49 -06003716 /* We should turn off LED before polling FF51[4]. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003717
Larry Finger19941302010-01-25 13:11:49 -06003718 /* Turn off LED. */
3719 btPSR = read_nic_byte(dev, PSR);
3720 write_nic_byte(dev, PSR, (btPSR & ~BIT3));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003721
Larry Finger19941302010-01-25 13:11:49 -06003722 /* It need to delay 4us suggested by Jong, 2008-01-16 */
3723 udelay(4);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003724
Larry Finger19941302010-01-25 13:11:49 -06003725 /* HW radio On/Off according to the value of FF51[4](config0) */
3726 btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003727
Larry Finger19941302010-01-25 13:11:49 -06003728 eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003729
Larry Finger6de92dd2010-02-11 14:41:24 -06003730 /* Turn LED back on when radio enabled */
3731 if (eRfPowerStateToSet == eRfOn)
3732 write_nic_byte(dev, PSR, btPSR | BIT3);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003733
Larry Finger19941302010-01-25 13:11:49 -06003734 if ((priv->ieee80211->bHwRadioOff == true) &&
3735 (eRfPowerStateToSet == eRfOn)) {
3736 priv->ieee80211->bHwRadioOff = false;
3737 bActuallySet = true;
3738 } else if ((priv->ieee80211->bHwRadioOff == false) &&
3739 (eRfPowerStateToSet == eRfOff)) {
3740 priv->ieee80211->bHwRadioOff = true;
3741 bActuallySet = true;
3742 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003743
Larry Finger19941302010-01-25 13:11:49 -06003744 if (bActuallySet) {
3745 MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003746
Larry Finger19941302010-01-25 13:11:49 -06003747 /* To update the UI status for Power status changed */
3748 if (priv->ieee80211->bHwRadioOff == true)
3749 argv[1] = "RFOFF";
3750 else
3751 argv[1] = "RFON";
3752 argv[0] = RadioPowerPath;
3753 argv[2] = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003754
Oleg Nesterov70834d32012-03-23 15:02:46 -07003755 call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
Larry Finger19941302010-01-25 13:11:49 -06003756 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003757}
3758
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003759module_init(rtl8180_pci_module_init);
3760module_exit(rtl8180_pci_module_exit);