blob: 8d767f35ce89103a602a907cbb5cc4d261784452 [file] [log] [blame]
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001/*
2 This is part of rtl818x pci OpenSource driver - v 0.1
Andrea Merello559a4c32013-08-26 13:53:30 +02003 Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08004 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);
Andrea Merello559a4c32013-08-26 13:53:30 +020073MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300163 return 0xff&readb((u8 __iomem *)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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300168 return readl((u8 __iomem *)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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300173 return readw((u8 __iomem *)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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300178 writeb(y, (u8 __iomem *)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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300184 writel(y, (u8 __iomem *)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{
Teodora Baluta8e87b1b2013-10-19 21:09:46 +0300190 writew(y, (u8 __iomem *)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
navin patidar9fc09442013-08-23 18:24:02 +0530200static irqreturn_t rtl8180_interrupt(int irq, void *netdev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800201void 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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300278static void rtl8180_proc_module_init(void)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800279{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300284static void rtl8180_proc_module_remove(void)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800285{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300289static void rtl8180_proc_remove_one(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800290{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300328static void rtl8180_proc_init_one(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800329{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300354static short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma,
355 struct buffer **bufferhead)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800356{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300466static short check_nic_enought_desc(struct net_device *dev, int priority)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800467{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300592static void rtl8180_irq_disable(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800593{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300708static short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
709 int addr)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800710{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300833static void free_tx_desc_rings(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800834{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300869static void free_rx_desc_ring(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800870{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +0300881static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -0800882{
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 */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001095static long 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 */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001131static long 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 */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001148static void 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 */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001173static void rtl8180_rx(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001174{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001499static void rtl8180_dma_kick(struct net_device *dev, int priority)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001500{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001511static void rtl8180_data_hard_stop(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001512{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001521static void rtl8180_data_hard_resume(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001522{
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 */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001535static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
1536 int rate)
1537{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001538 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
1539 int mode;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301540 struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
Larry Fingerb6b1ac62010-01-14 13:13:47 -06001541 short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001542 unsigned long flags;
1543 int priority;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001544
1545 mode = priv->ieee80211->iw_mode;
1546
1547 rate = ieeerate2rtlrate(rate);
1548 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301549 * This function doesn't require lock because we make
1550 * sure it's called with the tx_lock already acquired.
1551 * this come from the kernel's hard_xmit callback (through
1552 * the ieee stack, or from the try_wake_queue (again through
1553 * the ieee stack.
1554 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001555 priority = AC2Q(skb->priority);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301556 spin_lock_irqsave(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001557
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301558 if (priv->ieee80211->bHwRadioOff) {
1559 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001560
1561 return;
1562 }
1563
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301564 if (!check_nic_enought_desc(dev, priority)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001565 DMESGW("Error: no descriptor left by previous TX (avail %d) ",
1566 get_curr_tx_free_desc(dev, priority));
George Kadianakisdf574b82009-12-17 01:16:00 +02001567 ieee80211_rtl_stop_queue(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001568 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301569 rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001570 if (!check_nic_enought_desc(dev, priority))
George Kadianakisdf574b82009-12-17 01:16:00 +02001571 ieee80211_rtl_stop_queue(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001572
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301573 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001574}
1575
Andrew Millercd686802012-03-14 18:26:57 -04001576/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301577 * This is a rough attempt to TX a frame
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001578 * This is called by the ieee 80211 stack to TX management frames.
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001579 * If the ring is full packets are dropped (for data frame the queue
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001580 * is stopped before this can happen). For this reason it is better
1581 * if the descriptors are larger than the largest management frame
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001582 * we intend to TX: i'm unsure what the HW does if it will not find
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001583 * the last fragment of a frame because it has been dropped...
1584 * Since queues for Management and Data frames are different we
1585 * might use a different lock than tx_lock (for example mgmt_tx_lock)
1586 */
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07001587/* these function may loop if invoked with 0 descriptors or 0 len buffer */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001588static int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001589{
1590 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001591 unsigned long flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001592 int priority;
1593
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001594 priority = MANAGE_PRIORITY;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001595
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301596 spin_lock_irqsave(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001597
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001598 if (priv->ieee80211->bHwRadioOff) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301599 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001600 dev_kfree_skb_any(skb);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001601 return NETDEV_TX_OK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001602 }
1603
1604 rtl8180_tx(dev, skb->data, skb->len, priority,
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301605 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001606
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301607 priv->ieee80211->stats.tx_bytes += skb->len;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001608 priv->ieee80211->stats.tx_packets++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301609 spin_unlock_irqrestore(&priv->tx_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001610
1611 dev_kfree_skb_any(skb);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001612 return NETDEV_TX_OK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001613}
1614
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301615/* longpre 144+48 shortpre 72+24 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301616u16 rtl8180_len2duration(u32 len, short rate, short *ext)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001617{
1618 u16 duration;
1619 u16 drift;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301620 *ext = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001621
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301622 switch (rate) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301623 case 0: /* 1mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301624 *ext = 0;
1625 duration = ((len+4)<<4) / 0x2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001626 drift = ((len+4)<<4) % 0x2;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301627 if (drift == 0)
1628 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001629 duration++;
1630 break;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301631 case 1: /* 2mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301632 *ext = 0;
1633 duration = ((len+4)<<4) / 0x4;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001634 drift = ((len+4)<<4) % 0x4;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301635 if (drift == 0)
1636 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001637 duration++;
1638 break;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301639 case 2: /* 5.5mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301640 *ext = 0;
1641 duration = ((len+4)<<4) / 0xb;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001642 drift = ((len+4)<<4) % 0xb;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301643 if (drift == 0)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001644 break;
1645 duration++;
1646 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001647 default:
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301648 case 3: /* 11mbps */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301649 *ext = 0;
1650 duration = ((len+4)<<4) / 0x16;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001651 drift = ((len+4)<<4) % 0x16;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301652 if (drift == 0)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001653 break;
1654 duration++;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301655 if (drift > 6)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001656 break;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301657 *ext = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001658 break;
1659 }
1660
1661 return duration;
1662}
1663
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001664static void rtl8180_prepare_beacon(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001665{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001666 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001667 struct sk_buff *skb;
1668
1669 u16 word = read_nic_word(dev, BcnItv);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301670 word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
1671 word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001672 write_nic_word(dev, BcnItv, word);
1673
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001674 skb = ieee80211_get_beacon(priv->ieee80211);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301675 if (skb) {
1676 rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY,
1677 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001678 dev_kfree_skb_any(skb);
1679 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001680}
1681
Andrew Millercd686802012-03-14 18:26:57 -04001682/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301683 * This function do the real dirty work: it enqueues a TX command
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001684 * descriptor in the ring buffer, copyes the frame in a TX buffer
1685 * and kicks the NIC to ensure it does the DMA transfer.
1686 */
YAMANE Toshiakiac8bc122012-11-22 09:06:50 +09001687short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001688 short morefrag, short descfrag, int rate)
1689{
1690 struct r8180_priv *priv = ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301691 u32 *tail, *temp_tail;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001692 u32 *begin;
1693 u32 *buf;
1694 int i;
1695 int remain;
1696 int buflen;
1697 int count;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301698 struct buffer *buflist;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001699 struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
1700 u8 dest[ETH_ALEN];
1701 u8 bUseShortPreamble = 0;
1702 u8 bCTSEnable = 0;
1703 u8 bRTSEnable = 0;
John Churchcb73da22010-04-08 16:04:17 -05001704 u16 Duration = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001705 u16 RtsDur = 0;
1706 u16 ThisFrameTime = 0;
1707 u16 TxDescDuration = 0;
Peter Senna Tschudinb6c5d772013-09-22 00:27:47 +02001708 bool ownbit_flag = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001709
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301710 switch (priority) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001711 case MANAGE_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301712 tail = priv->txmapringtail;
1713 begin = priv->txmapring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001714 buflist = priv->txmapbufstail;
1715 count = priv->txringcount;
1716 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001717 case BK_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301718 tail = priv->txbkpringtail;
1719 begin = priv->txbkpring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001720 buflist = priv->txbkpbufstail;
1721 count = priv->txringcount;
1722 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001723 case BE_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301724 tail = priv->txbepringtail;
1725 begin = priv->txbepring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001726 buflist = priv->txbepbufstail;
1727 count = priv->txringcount;
1728 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001729 case VI_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301730 tail = priv->txvipringtail;
1731 begin = priv->txvipring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001732 buflist = priv->txvipbufstail;
1733 count = priv->txringcount;
1734 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001735 case VO_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301736 tail = priv->txvopringtail;
1737 begin = priv->txvopring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001738 buflist = priv->txvopbufstail;
1739 count = priv->txringcount;
1740 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001741 case HI_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301742 tail = priv->txhpringtail;
1743 begin = priv->txhpring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001744 buflist = priv->txhpbufstail;
1745 count = priv->txringcount;
1746 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001747 case BEACON_PRIORITY:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301748 tail = priv->txbeaconringtail;
1749 begin = priv->txbeaconring;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001750 buflist = priv->txbeaconbufstail;
1751 count = priv->txbeaconcount;
1752 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001753 default:
1754 return -1;
1755 break;
John Churchcb73da22010-04-08 16:04:17 -05001756 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001757
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001758 memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
Joe Perches14fc4232012-05-08 10:11:56 -07001759 if (is_multicast_ether_addr(dest)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001760 Duration = 0;
1761 RtsDur = 0;
1762 bRTSEnable = 0;
1763 bCTSEnable = 0;
1764
Andrew Millerdec3a002012-03-14 18:26:59 -04001765 ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
1766 0, bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001767 TxDescDuration = ThisFrameTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301768 } else { /* Unicast packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001769 u16 AckTime;
1770
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301771 /* YJ,add,080828,for Keep alive */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001772 priv->NumTxUnicast++;
1773
Larry Finger19941302010-01-25 13:11:49 -06001774 /* Figure out ACK rate according to BSS basic rate
1775 * and Tx rate. */
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301776 AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001777
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301778 if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001779 u16 RtsTime, CtsTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301780 /* u16 CtsRate; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001781 bRTSEnable = 1;
1782 bCTSEnable = 0;
1783
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301784 /* Rate and time required for RTS. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301785 RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301786 /* Rate and time required for CTS. */
1787 CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001788
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301789 /* Figure out time required to transmit this frame. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001790 ThisFrameTime = ComputeTxTime(len + sCrcLng,
1791 rtl8180_rate2rate(rate),
1792 0,
1793 bUseShortPreamble);
1794
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301795 /* RTS-CTS-ThisFrame-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001796 RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
1797
1798 TxDescDuration = RtsTime + RtsDur;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301799 } else { /* Normal case. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001800 bCTSEnable = 0;
1801 bRTSEnable = 0;
1802 RtsDur = 0;
1803
Andrew Millerdec3a002012-03-14 18:26:59 -04001804 ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
1805 0, bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001806 TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
1807 }
1808
Larry Fingerb6b1ac62010-01-14 13:13:47 -06001809 if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301810 /* ThisFrame-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001811 Duration = aSifsTime + AckTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301812 } else { /* One or more fragments remained. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001813 u16 NextFragTime;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301814 NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001815 rtl8180_rate2rate(rate),
1816 0,
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301817 bUseShortPreamble);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001818
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301819 /* ThisFrag-ACk-NextFrag-ACK. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001820 Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
1821 }
1822
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301823 } /* End of Unicast packet */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001824
1825 frag_hdr->duration_id = Duration;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001826
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301827 buflen = priv->txbuffsize;
1828 remain = len;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001829 temp_tail = tail;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001830
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301831 while (remain != 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001832 mb();
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301833 if (!buflist) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001834 DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001835 return -1;
1836 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301837 buf = buflist->buf;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001838
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001839 if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) {
1840 DMESGW("No more TX desc, returning %x of %x",
1841 remain, len);
1842 priv->stats.txrdu++;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001843 return remain;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001844 }
1845
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301846 *tail = 0; /* zeroes header */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001847 *(tail+1) = 0;
1848 *(tail+3) = 0;
1849 *(tail+5) = 0;
1850 *(tail+6) = 0;
1851 *(tail+7) = 0;
1852
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301853 /* FIXME: this should be triggered by HW encryption parameters.*/
Larry Fingerd44eb882009-11-09 10:53:20 -06001854 *tail |= (1<<15); /* no encrypt */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001855
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301856 if (remain == len && !descfrag) {
Larry Finger19941302010-01-25 13:11:49 -06001857 ownbit_flag = false;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301858 *tail = *tail | (1<<29) ; /* fist segment of the packet */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301859 *tail = *tail | (len);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001860 } else {
1861 ownbit_flag = true;
1862 }
1863
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301864 for (i = 0; i < buflen && remain > 0; i++, remain--) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301865 ((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301866 if (remain == 4 && i+4 >= buflen)
1867 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001868 /* ensure the last desc has at least 4 bytes payload */
1869
1870 }
1871 txbuf = txbuf + i;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301872 *(tail+3) = *(tail+3) & ~0xfff;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301873 *(tail+3) = *(tail+3) | i; /* buffer length */
1874 /* Use short preamble or not */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001875 if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301876 if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
1877 ; /* *tail |= (1<<16); */ /* enable short preamble mode. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001878
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301879 if (bCTSEnable)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001880 *tail |= (1<<18);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001881
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301882 if (bRTSEnable) { /* rts enable */
1883 *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
1884 *tail |= (1<<23); /* rts enable */
1885 *(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001886 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301887 *(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
1888 /* *(tail+3) |= (0xe6<<16); */
1889 *(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001890
1891 *tail = *tail | ((rate&0xf) << 24);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001892
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301893 if (morefrag)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301894 *tail = (*tail) | (1<<17); /* more fragment */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301895 if (!remain)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301896 *tail = (*tail) | (1<<28); /* last segment of frame */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001897
John Churchcb73da22010-04-08 16:04:17 -05001898 *(tail+5) = *(tail+5)|(2<<27);
1899 *(tail+7) = *(tail+7)|(1<<4);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001900
1901 wmb();
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301902 if (ownbit_flag)
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301903 *tail = *tail | (1<<31); /* descriptor ready to be txed */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001904
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301905 if ((tail - begin)/8 == count-1)
1906 tail = begin;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001907 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301908 tail = tail+8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001909
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301910 buflist = buflist->next;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001911
1912 mb();
1913
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301914 switch (priority) {
1915 case MANAGE_PRIORITY:
1916 priv->txmapringtail = tail;
1917 priv->txmapbufstail = buflist;
1918 break;
1919 case BK_PRIORITY:
1920 priv->txbkpringtail = tail;
1921 priv->txbkpbufstail = buflist;
1922 break;
1923 case BE_PRIORITY:
1924 priv->txbepringtail = tail;
1925 priv->txbepbufstail = buflist;
1926 break;
1927 case VI_PRIORITY:
1928 priv->txvipringtail = tail;
1929 priv->txvipbufstail = buflist;
1930 break;
1931 case VO_PRIORITY:
1932 priv->txvopringtail = tail;
1933 priv->txvopbufstail = buflist;
1934 break;
1935 case HI_PRIORITY:
1936 priv->txhpringtail = tail;
1937 priv->txhpbufstail = buflist;
1938 break;
1939 case BEACON_PRIORITY:
Andrew Millercd686802012-03-14 18:26:57 -04001940 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301941 * The HW seems to be happy with the 1st
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301942 * descriptor filled and the 2nd empty...
1943 * So always update descriptor 1 and never
1944 * touch 2nd
1945 */
1946 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001947 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001948 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05301949 *temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301950 rtl8180_dma_kick(dev, priority);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001951
1952 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001953}
1954
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301955void rtl8180_irq_rx_tasklet(struct r8180_priv *priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001956
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001957static void rtl8180_link_change(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001958{
1959 struct r8180_priv *priv = ieee80211_priv(dev);
1960 u16 beacon_interval;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001961 struct ieee80211_network *net = &priv->ieee80211->current_network;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001962
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001963 rtl8180_update_msr(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001964
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301965 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001966
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301967 write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]);
1968 write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001969
Maxim Mikityanskiyfbce4282012-11-13 19:28:22 +02001970 beacon_interval = read_nic_word(dev, BEACON_INTERVAL);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301971 beacon_interval &= ~BEACON_INTERVAL_MASK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001972 beacon_interval |= net->beacon_interval;
Maxim Mikityanskiyfbce4282012-11-13 19:28:22 +02001973 write_nic_word(dev, BEACON_INTERVAL, beacon_interval);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001974
1975 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
1976
Larry Fingerd44eb882009-11-09 10:53:20 -06001977 rtl8180_set_chan(dev, priv->chan);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001978}
1979
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001980static void rtl8180_rq_tx_ack(struct net_device *dev)
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301981{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001982
1983 struct r8180_priv *priv = ieee80211_priv(dev);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02001984
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301985 write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001986 priv->ack_tx_to_ieee = 1;
1987}
1988
Teodora Baluta17ab33e2013-10-19 21:09:47 +03001989static short rtl8180_is_tx_queue_empty(struct net_device *dev)
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301990{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001991
1992 struct r8180_priv *priv = ieee80211_priv(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301993 u32 *d;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001994
1995 for (d = priv->txmapring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05301996 d < priv->txmapring + priv->txringcount; d += 8)
1997 if (*d & (1<<31))
1998 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08001999
2000 for (d = priv->txbkpring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302001 d < priv->txbkpring + priv->txringcount; d += 8)
2002 if (*d & (1<<31))
2003 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002004
2005 for (d = priv->txbepring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302006 d < priv->txbepring + priv->txringcount; d += 8)
2007 if (*d & (1<<31))
2008 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002009
2010 for (d = priv->txvipring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302011 d < priv->txvipring + priv->txringcount; d += 8)
2012 if (*d & (1<<31))
2013 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002014
2015 for (d = priv->txvopring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302016 d < priv->txvopring + priv->txringcount; d += 8)
2017 if (*d & (1<<31))
2018 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002019
2020 for (d = priv->txhpring;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302021 d < priv->txhpring + priv->txringcount; d += 8)
2022 if (*d & (1<<31))
2023 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002024 return 1;
2025}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002026
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002027static void rtl8180_hw_wakeup(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002028{
2029 unsigned long flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002030 struct r8180_priv *priv = ieee80211_priv(dev);
2031
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302032 spin_lock_irqsave(&priv->ps_lock, flags);
2033 write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002034 if (priv->rf_wakeup)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002035 priv->rf_wakeup(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302036 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002037}
2038
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002039static void rtl8180_hw_sleep_down(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002040{
John Churchcb73da22010-04-08 16:04:17 -05002041 unsigned long flags;
2042 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002043
John Churchcb73da22010-04-08 16:04:17 -05002044 spin_lock_irqsave(&priv->ps_lock, flags);
2045 if (priv->rf_sleep)
2046 priv->rf_sleep(dev);
2047 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002048}
2049
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002050static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002051{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002052 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002053 u32 rb = jiffies;
2054 unsigned long flags;
2055
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302056 spin_lock_irqsave(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002057
Andrew Millercd686802012-03-14 18:26:57 -04002058 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302059 * Writing HW register with 0 equals to disable
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002060 * the timer, that is not really what we want
2061 */
2062 tl -= MSECS(4+16+7);
2063
Andrew Millercd686802012-03-14 18:26:57 -04002064 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302065 * If the interval in witch we are requested to sleep is too
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002066 * short then give up and remain awake
2067 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302068 if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
2069 || ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
2070 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002071 printk("too short to sleep\n");
2072 return;
2073 }
2074
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002075 {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302076 u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002077
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002078 priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
Andrew Millerdec3a002012-03-14 18:26:59 -04002079 /* as tl may be less than rb */
2080 queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002081 }
Andrew Millercd686802012-03-14 18:26:57 -04002082 /*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302083 * If we suspect the TimerInt is gone beyond tl
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002084 * while setting it, then give up
2085 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002086
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302087 if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) ||
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002088 ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302089 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002090 return;
2091 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002092
2093 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302094 spin_unlock_irqrestore(&priv->ps_lock, flags);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002095}
2096
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002097static void rtl8180_wmm_param_update(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002098{
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302099 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002100 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002101 u8 *ac_param = (u8 *)(ieee->current_network.wmm_param);
2102 u8 mode = ieee->current_network.mode;
2103 AC_CODING eACI;
2104 AC_PARAM AcParam;
2105 PAC_PARAM pAcParam;
2106 u8 i;
2107
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302108 if (!ieee->current_network.QoS_Enable) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302109 /* legacy ac_xx_param update */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002110 AcParam.longData = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302111 AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002112 AcParam.f.AciAifsn.f.ACM = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302113 AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
2114 AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002115 AcParam.f.TXOPLimit = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302116 for (eACI = 0; eACI < AC_MAX; eACI++) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002117 AcParam.f.AciAifsn.f.ACI = (u8)eACI;
2118 {
2119 u8 u1bAIFS;
2120 u32 u4bAcParam;
2121 pAcParam = (PAC_PARAM)(&AcParam);
Masanari Iida3d604a32012-08-10 01:06:54 +09002122 /* Retrieve parameters to update. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302123 u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002124 u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
2125 (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
2126 (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
2127 (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302128 switch (eACI) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002129 case AC1_BK:
2130 write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
2131 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002132 case AC0_BE:
2133 write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
2134 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002135 case AC2_VI:
2136 write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
2137 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002138 case AC3_VO:
2139 write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
2140 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002141 default:
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09002142 pr_warn("SetHwReg8185():invalid ACI: %d!\n",
2143 eACI);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002144 break;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302145 }
2146 }
2147 }
2148 return;
2149 }
2150
2151 for (i = 0; i < AC_MAX; i++) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302152 /* AcParam.longData = 0; */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302153 pAcParam = (AC_PARAM *)ac_param;
2154 {
2155 AC_CODING eACI;
2156 u8 u1bAIFS;
2157 u32 u4bAcParam;
2158
Masanari Iida3d604a32012-08-10 01:06:54 +09002159 /* Retrieve parameters to update. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302160 eACI = pAcParam->f.AciAifsn.f.ACI;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302161 /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302162 u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
2163 u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
2164 (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
2165 (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
2166 (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
2167
2168 switch (eACI) {
2169 case AC1_BK:
2170 write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
2171 break;
2172 case AC0_BE:
2173 write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
2174 break;
2175 case AC2_VI:
2176 write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
2177 break;
2178 case AC3_VO:
2179 write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
2180 break;
2181 default:
YAMANE Toshiakife5388c2012-11-22 09:07:04 +09002182 pr_warn("SetHwReg8185(): invalid ACI: %d !\n",
2183 eACI);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302184 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002185 }
2186 }
2187 ac_param += (sizeof(AC_PARAM));
2188 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002189}
2190
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002191void rtl8180_restart_wq(struct work_struct *work);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302192/* void rtl8180_rq_tx_ack(struct work_struct *work); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002193void rtl8180_watch_dog_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002194void rtl8180_hw_wakeup_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002195void rtl8180_hw_sleep_wq(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002196void rtl8180_sw_antenna_wq(struct work_struct *work);
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02002197void rtl8180_watch_dog(struct net_device *dev);
2198
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002199static void watch_dog_adaptive(unsigned long data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002200{
YAMANE Toshiakiac8bc122012-11-22 09:06:50 +09002201 struct r8180_priv *priv = ieee80211_priv((struct net_device *)data);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002202
2203 if (!priv->up) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002204 DMESG("<----watch_dog_adaptive():driver is not up!\n");
2205 return;
2206 }
2207
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302208 /* Tx High Power Mechanism. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302209 if (CheckHighPower((struct net_device *)data))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002210 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002211
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302212 /* Tx Power Tracking on 87SE. */
Dan Carpentercffd4e12010-01-18 14:23:20 +03002213 if (CheckTxPwrTracking((struct net_device *)data))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002214 TxPwrTracking87SE((struct net_device *)data);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002215
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302216 /* Perform DIG immediately. */
Teodora Baluta0fe249a2013-10-25 12:00:16 +03002217 if (CheckDig((struct net_device *)data))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002218 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302219 rtl8180_watch_dog((struct net_device *)data);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002220
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002221 queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
2222
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302223 priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002224 add_timer(&priv->watch_dog_timer);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002225}
2226
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002227static CHANNEL_LIST ChannelPlan[] = {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302228 {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */
2229 {{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */
2230 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */
2231 {{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. */
2232 {{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. */
2233 {{14,36,40,44,48,52,56,60,64},9}, /* MKK */
2234 {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */
2235 {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */
2236 {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */
2237 {{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 */
2238 {{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 -08002239};
2240
2241static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
2242{
2243 int i;
2244
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302245 /* lzm add 080826 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302246 ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1;
2247 ieee->IbssStartChnl = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002248
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302249 switch (channel_plan) {
2250 case COUNTRY_CODE_FCC:
2251 case COUNTRY_CODE_IC:
2252 case COUNTRY_CODE_ETSI:
2253 case COUNTRY_CODE_SPAIN:
2254 case COUNTRY_CODE_FRANCE:
2255 case COUNTRY_CODE_MKK:
2256 case COUNTRY_CODE_MKK1:
2257 case COUNTRY_CODE_ISRAEL:
2258 case COUNTRY_CODE_TELEC:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002259 {
2260 Dot11d_Init(ieee);
2261 ieee->bGlobalDomain = false;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302262 if (ChannelPlan[channel_plan].Len != 0) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302263 /* Clear old channel map */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002264 memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302265 /* Set new channel map */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302266 for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
2267 if (ChannelPlan[channel_plan].Channel[i] <= 14)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002268 GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
2269 }
2270 }
2271 break;
2272 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302273 case COUNTRY_CODE_GLOBAL_DOMAIN:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002274 {
Teodora Balutaf2684292013-10-25 12:00:15 +03002275 GET_DOT11D_INFO(ieee)->bEnabled = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002276 Dot11d_Reset(ieee);
2277 ieee->bGlobalDomain = true;
2278 break;
2279 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302280 case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002281 {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302282 ieee->MinPassiveChnlNum = 12;
2283 ieee->IbssStartChnl = 10;
2284 break;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002285 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302286 default:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002287 {
2288 Dot11d_Init(ieee);
2289 ieee->bGlobalDomain = false;
2290 memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302291 for (i = 1; i <= 14; i++)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002292 GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002293 break;
2294 }
2295 }
2296}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002297
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002298void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002299
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302300/* YJ,add,080828 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002301static void rtl8180_statistics_init(struct Stats *pstats)
2302{
2303 memset(pstats, 0, sizeof(struct Stats));
2304}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002305
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002306static void rtl8180_link_detect_init(plink_detect_t plink_detect)
2307{
2308 memset(plink_detect, 0, sizeof(link_detect_t));
2309 plink_detect->SlotNum = DEFAULT_SLOT_NUM;
2310}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002311
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302312/* YJ,add,080828,end */
Larry Finger742821c2010-02-11 12:07:35 -06002313static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
2314{
2315 struct net_device *dev = eeprom->data;
2316 u8 reg = read_nic_byte(dev, EPROM_CMD);
2317
2318 eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
2319 eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
2320 eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
2321 eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
2322}
2323
2324static void rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom)
2325{
2326 struct net_device *dev = eeprom->data;
2327 u8 reg = 2 << 6;
2328
2329 if (eeprom->reg_data_in)
2330 reg |= RTL818X_EEPROM_CMD_WRITE;
2331 if (eeprom->reg_data_out)
2332 reg |= RTL818X_EEPROM_CMD_READ;
2333 if (eeprom->reg_data_clock)
2334 reg |= RTL818X_EEPROM_CMD_CK;
2335 if (eeprom->reg_chip_select)
2336 reg |= RTL818X_EEPROM_CMD_CS;
2337
2338 write_nic_byte(dev, EPROM_CMD, reg);
2339 read_nic_byte(dev, EPROM_CMD);
2340 udelay(10);
2341}
2342
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002343short rtl8180_init(struct net_device *dev)
2344{
2345 struct r8180_priv *priv = ieee80211_priv(dev);
2346 u16 word;
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002347 u16 usValue;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002348 u16 tmpu16;
2349 int i, j;
Larry Finger742821c2010-02-11 12:07:35 -06002350 struct eeprom_93cx6 eeprom;
2351 u16 eeprom_val;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002352
Larry Finger742821c2010-02-11 12:07:35 -06002353 eeprom.data = dev;
2354 eeprom.register_read = rtl8187se_eeprom_register_read;
2355 eeprom.register_write = rtl8187se_eeprom_register_write;
2356 eeprom.width = PCI_EEPROM_WIDTH_93C46;
2357
2358 eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
2359 priv->channel_plan = eeprom_val & 0xFF;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302360 if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002361 printk("rtl8180_init:Error channel plan! Set to default.\n");
2362 priv->channel_plan = 0;
2363 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002364
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302365 DMESG("Channel plan is %d\n", priv->channel_plan);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002366 rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002367
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302368 /* FIXME: these constants are placed in a bad pleace. */
2369 priv->txbuffsize = 2048; /* 1024; */
2370 priv->txringcount = 32; /* 32; */
2371 priv->rxbuffersize = 2048; /* 1024; */
2372 priv->rxringcount = 64; /* 32; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002373 priv->txbeaconcount = 2;
2374 priv->rx_skb_complete = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002375
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002376 priv->RFChangeInProgress = false;
2377 priv->SetRFPowerStateInProgress = false;
2378 priv->RFProgType = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002379
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302380 priv->irq_enabled = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002381
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002382 rtl8180_statistics_init(&priv->stats);
2383 rtl8180_link_detect_init(&priv->link_detect);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002384
2385 priv->ack_tx_to_ieee = 0;
2386 priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
2387 priv->ieee80211->iw_mode = IW_MODE_INFRA;
2388 priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN |
2389 IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
2390 IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;
2391 priv->ieee80211->active_scan = 1;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302392 priv->ieee80211->rate = 110; /* 11 mbps */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002393 priv->ieee80211->modulation = IEEE80211_CCK_MODULATION;
2394 priv->ieee80211->host_encrypt = 1;
2395 priv->ieee80211->host_decrypt = 1;
2396 priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup;
2397 priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack;
2398 priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep;
2399 priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty;
2400
2401 priv->hw_wep = hwwep;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302402 priv->dev = dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002403 priv->retry_rts = DEFAULT_RETRY_RTS;
2404 priv->retry_data = DEFAULT_RETRY_DATA;
2405 priv->RFChangeInProgress = false;
2406 priv->SetRFPowerStateInProgress = false;
2407 priv->RFProgType = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302408 priv->bInactivePs = true; /* false; */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002409 priv->ieee80211->bInactivePs = priv->bInactivePs;
2410 priv->bSwRfProcessing = false;
2411 priv->eRFPowerState = eRfOff;
2412 priv->RfOffReason = 0;
2413 priv->LedStrategy = SW_LED_MODE0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302414 priv->TxPollingTimes = 0; /* lzm add 080826 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002415 priv->bLeisurePs = true;
2416 priv->dot11PowerSaveMode = eActive;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002417 priv->AdMinCheckPeriod = 5;
2418 priv->AdMaxCheckPeriod = 10;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302419 priv->AdMaxRxSsThreshold = 30; /* 60->30 */
2420 priv->AdRxSsThreshold = 20; /* 50->20 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002421 priv->AdCheckPeriod = priv->AdMinCheckPeriod;
2422 priv->AdTickCount = 0;
2423 priv->AdRxSignalStrength = -1;
2424 priv->RegSwAntennaDiversityMechanism = 0;
2425 priv->RegDefaultAntenna = 0;
2426 priv->SignalStrength = 0;
2427 priv->AdRxOkCnt = 0;
2428 priv->CurrAntennaIndex = 0;
2429 priv->AdRxSsBeforeSwitched = 0;
2430 init_timer(&priv->SwAntennaDiversityTimer);
2431 priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
2432 priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
Teodora Balutaf2684292013-10-25 12:00:15 +03002433 priv->bDigMechanism = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002434 priv->InitialGain = 6;
2435 priv->bXtalCalibration = false;
2436 priv->XtalCal_Xin = 0;
2437 priv->XtalCal_Xout = 0;
2438 priv->bTxPowerTrack = false;
2439 priv->ThermalMeter = 0;
2440 priv->FalseAlarmRegValue = 0;
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07002441 priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002442 priv->DIG_NumberFallbackVote = 0;
2443 priv->DIG_NumberUpgradeVote = 0;
2444 priv->LastSignalStrengthInPercent = 0;
2445 priv->Stats_SignalStrength = 0;
2446 priv->LastRxPktAntenna = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302447 priv->SignalQuality = 0; /* in 0-100 index. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002448 priv->Stats_SignalQuality = 0;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302449 priv->RecvSignalPower = 0; /* in dBm. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002450 priv->Stats_RecvSignalPower = 0;
2451 priv->AdMainAntennaRxOkCnt = 0;
2452 priv->AdAuxAntennaRxOkCnt = 0;
2453 priv->bHWAdSwitched = false;
2454 priv->bRegHighPowerMechanism = true;
2455 priv->RegHiPwrUpperTh = 77;
2456 priv->RegHiPwrLowerTh = 75;
2457 priv->RegRSSIHiPwrUpperTh = 70;
2458 priv->RegRSSIHiPwrLowerTh = 20;
2459 priv->bCurCCKPkt = false;
2460 priv->UndecoratedSmoothedSS = -1;
2461 priv->bToUpdateTxPwr = false;
2462 priv->CurCCKRSSI = 0;
2463 priv->RxPower = 0;
2464 priv->RSSI = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002465 priv->NumTxOkTotal = 0;
2466 priv->NumTxUnicast = 0;
2467 priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
Larry Finger19941302010-01-25 13:11:49 -06002468 priv->CurrRetryCnt = 0;
2469 priv->LastRetryCnt = 0;
2470 priv->LastTxokCnt = 0;
2471 priv->LastRxokCnt = 0;
2472 priv->LastRetryRate = 0;
2473 priv->bTryuping = 0;
2474 priv->CurrTxRate = 0;
2475 priv->CurrRetryRate = 0;
2476 priv->TryupingCount = 0;
2477 priv->TryupingCountNoData = 0;
2478 priv->TryDownCountLowData = 0;
2479 priv->LastTxOKBytes = 0;
2480 priv->LastFailTxRate = 0;
2481 priv->LastFailTxRateSS = 0;
2482 priv->FailTxRateCount = 0;
2483 priv->LastTxThroughput = 0;
2484 priv->NumTxOkBytesTotal = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002485 priv->ForcedDataRate = 0;
2486 priv->RegBModeGainStage = 1;
2487
Larry Finger19941302010-01-25 13:11:49 -06002488 priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002489 spin_lock_init(&priv->irq_th_lock);
2490 spin_lock_init(&priv->tx_lock);
2491 spin_lock_init(&priv->ps_lock);
2492 spin_lock_init(&priv->rf_ps_lock);
Larry Finger19941302010-01-25 13:11:49 -06002493 sema_init(&priv->wx_sem, 1);
Larry Finger19941302010-01-25 13:11:49 -06002494 INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq);
Larry Finger19941302010-01-25 13:11:49 -06002495 INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,
2496 (void *)rtl8180_hw_wakeup_wq);
2497 INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,
2498 (void *)rtl8180_hw_sleep_wq);
2499 INIT_WORK(&priv->ieee80211->wmm_param_update_wq,
2500 (void *)rtl8180_wmm_param_update);
2501 INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,
2502 (void *)rtl8180_rate_adapter);
2503 INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,
2504 (void *)rtl8180_hw_dig_wq);
2505 INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,
2506 (void *)rtl8180_tx_pw_wq);
2507 INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,
2508 (void *) GPIOChangeRFWorkItemCallBack);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002509 tasklet_init(&priv->irq_rx_tasklet,
2510 (void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
2511 (unsigned long)priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002512
Larry Finger19941302010-01-25 13:11:49 -06002513 init_timer(&priv->watch_dog_timer);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002514 priv->watch_dog_timer.data = (unsigned long)dev;
2515 priv->watch_dog_timer.function = watch_dog_adaptive;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002516
Larry Finger19941302010-01-25 13:11:49 -06002517 init_timer(&priv->rateadapter_timer);
2518 priv->rateadapter_timer.data = (unsigned long)dev;
2519 priv->rateadapter_timer.function = timer_rate_adaptive;
2520 priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
2521 priv->bEnhanceTxPwr = false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002522
2523 priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit;
2524 priv->ieee80211->set_chan = rtl8180_set_chan;
2525 priv->ieee80211->link_change = rtl8180_link_change;
2526 priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit;
2527 priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop;
2528 priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume;
2529
John Churchcb73da22010-04-08 16:04:17 -05002530 priv->ieee80211->init_wmmparam_flag = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002531
2532 priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon;
2533 priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable;
2534 priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
2535
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002536 priv->ShortRetryLimit = 7;
2537 priv->LongRetryLimit = 7;
2538 priv->EarlyRxThreshold = 7;
2539
Maxim Mikityanskiy42af4992012-11-13 19:28:16 +02002540 priv->TransmitConfig = (1<<TCR_DurProcMode_OFFSET) |
Larry Finger19941302010-01-25 13:11:49 -06002541 (7<<TCR_MXDMA_OFFSET) |
2542 (priv->ShortRetryLimit<<TCR_SRL_OFFSET) |
Maxim Mikityanskiy42af4992012-11-13 19:28:16 +02002543 (priv->LongRetryLimit<<TCR_LRL_OFFSET);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002544
Larry Finger19941302010-01-25 13:11:49 -06002545 priv->ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF |
2546 RCR_AB | RCR_AM | RCR_APM |
2547 (7<<RCR_MXDMA_OFFSET) |
2548 (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) |
2549 (priv->EarlyRxThreshold == 7 ?
2550 RCR_ONLYERLPKT : 0);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002551
2552 priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER |
Larry Finger19941302010-01-25 13:11:49 -06002553 IMR_THPDER | IMR_THPDOK |
2554 IMR_TVODER | IMR_TVODOK |
2555 IMR_TVIDER | IMR_TVIDOK |
2556 IMR_TBEDER | IMR_TBEDOK |
2557 IMR_TBKDER | IMR_TBKDOK |
2558 IMR_RDU |
2559 IMR_RER | IMR_ROK |
2560 IMR_RQoSOK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002561
2562 priv->InitialGain = 6;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002563
Larry Fingerd44eb882009-11-09 10:53:20 -06002564 DMESG("MAC controller is a RTL8187SE b/g");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002565
Larry Fingerd44eb882009-11-09 10:53:20 -06002566 priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION;
2567 priv->ieee80211->short_slot = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002568
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002569 eeprom_93cx6_read(&eeprom, EEPROM_SW_REVD_OFFSET, &usValue);
2570 DMESG("usValue is %#hx\n", usValue);
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302571 /* 3Read AntennaDiversity */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002572
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302573 /* SW Antenna Diversity. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002574 priv->EEPROMSwAntennaDiversity = (usValue & EEPROM_SW_AD_MASK) ==
2575 EEPROM_SW_AD_ENABLE;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002576
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302577 /* Default Antenna to use. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002578 priv->EEPROMDefaultAntenna1 = (usValue & EEPROM_DEF_ANT_MASK) ==
2579 EEPROM_DEF_ANT_1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002580
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302581 if (priv->RegSwAntennaDiversityMechanism == 0) /* Auto */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002582 /* 0: default from EEPROM. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002583 priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002584 else
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002585 /* 1:disable antenna diversity, 2: enable antenna diversity. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002586 priv->bSwAntennaDiverity = priv->RegSwAntennaDiversityMechanism == 2;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002587
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002588 if (priv->RegDefaultAntenna == 0)
2589 /* 0: default from EEPROM. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002590 priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002591 else
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002592 /* 1: main, 2: aux. */
Maxim Mikityanskiy3044e452012-11-13 19:28:20 +02002593 priv->bDefaultAntenna1 = priv->RegDefaultAntenna == 2;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002594
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002595 priv->plcp_preamble_mode = 2;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302596 /* the eeprom type is stored in RCR register bit #6 */
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002597 if (RCR_9356SEL & read_nic_dword(dev, RCR))
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302598 priv->epromtype = EPROM_93c56;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002599 else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302600 priv->epromtype = EPROM_93c46;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002601
Larry Finger742821c2010-02-11 12:07:35 -06002602 eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)
2603 dev->dev_addr, 3);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002604
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302605 for (i = 1, j = 0; i < 14; i += 2, j++) {
Larry Finger742821c2010-02-11 12:07:35 -06002606 eeprom_93cx6_read(&eeprom, EPROM_TXPW_CH1_2 + j, &word);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302607 priv->chtxpwr[i] = word & 0xff;
2608 priv->chtxpwr[i+1] = (word & 0xff00)>>8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002609 }
Larry Fingerd44eb882009-11-09 10:53:20 -06002610 for (i = 1, j = 0; i < 14; i += 2, j++) {
Larry Finger742821c2010-02-11 12:07:35 -06002611 eeprom_93cx6_read(&eeprom, EPROM_TXPW_OFDM_CH1_2 + j, &word);
Larry Fingerd44eb882009-11-09 10:53:20 -06002612 priv->chtxpwr_ofdm[i] = word & 0xff;
Larry Finger19941302010-01-25 13:11:49 -06002613 priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002614 }
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002615
Justin P. Mattocked2cb4f2012-04-17 06:56:43 -07002616 /* 3Read crystal calibration and thermal meter indication on 87SE. */
Larry Finger742821c2010-02-11 12:07:35 -06002617 eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002618
Larry Finger19941302010-01-25 13:11:49 -06002619 /* Crystal calibration for Xin and Xout resp. */
2620 priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK;
2621 priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK) >> 4;
2622 if ((tmpu16 & EEPROM_XTAL_CAL_ENABLE) >> 12)
2623 priv->bXtalCalibration = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002624
Larry Finger19941302010-01-25 13:11:49 -06002625 /* Thermal meter reference indication. */
2626 priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK) >> 8);
2627 if ((tmpu16 & EEPROM_THERMAL_METER_ENABLE) >> 13)
2628 priv->bTxPowerTrack = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002629
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002630 priv->rf_sleep = rtl8225z4_rf_sleep;
2631 priv->rf_wakeup = rtl8225z4_rf_wakeup;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002632 DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!");
2633
2634 priv->rf_close = rtl8225z2_rf_close;
2635 priv->rf_init = rtl8225z2_rf_init;
2636 priv->rf_set_chan = rtl8225z2_rf_set_chan;
2637 priv->rf_set_sens = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002638
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302639 if (0 != alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002640 return -ENOMEM;
2641
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302642 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002643 TX_MANAGEPRIORITY_RING_ADDR))
2644 return -ENOMEM;
2645
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302646 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002647 TX_BKPRIORITY_RING_ADDR))
2648 return -ENOMEM;
2649
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302650 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002651 TX_BEPRIORITY_RING_ADDR))
2652 return -ENOMEM;
2653
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302654 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002655 TX_VIPRIORITY_RING_ADDR))
2656 return -ENOMEM;
2657
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302658 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002659 TX_VOPRIORITY_RING_ADDR))
2660 return -ENOMEM;
2661
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302662 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002663 TX_HIGHPRIORITY_RING_ADDR))
2664 return -ENOMEM;
2665
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302666 if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002667 TX_BEACON_RING_ADDR))
2668 return -ENOMEM;
2669
navin patidar9fc09442013-08-23 18:24:02 +05302670 if (request_irq(dev->irq, rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
John Churchcb73da22010-04-08 16:04:17 -05002671 DMESGE("Error allocating IRQ %d", dev->irq);
2672 return -1;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302673 } else {
2674 priv->irq = dev->irq;
2675 DMESG("IRQ %d", dev->irq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002676 }
2677
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002678 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002679}
2680
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002681void rtl8180_no_hw_wep(struct net_device *dev)
2682{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002683}
2684
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002685void rtl8180_set_hw_wep(struct net_device *dev)
2686{
2687 struct r8180_priv *priv = ieee80211_priv(dev);
2688 u8 pgreg;
2689 u8 security;
2690 u32 key0_word4;
2691
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302692 pgreg = read_nic_byte(dev, PGSELECT);
2693 write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002694
2695 key0_word4 = read_nic_dword(dev, KEY0+4+4+4);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302696 key0_word4 &= ~0xff;
2697 key0_word4 |= priv->key0[3] & 0xff;
2698 write_nic_dword(dev, KEY0, (priv->key0[0]));
2699 write_nic_dword(dev, KEY0+4, (priv->key0[1]));
2700 write_nic_dword(dev, KEY0+4+4, (priv->key0[2]));
2701 write_nic_dword(dev, KEY0+4+4+4, (key0_word4));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002702
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302703 security = read_nic_byte(dev, SECURITY);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002704 security |= (1<<SECURITY_WEP_TX_ENABLE_SHIFT);
2705 security |= (1<<SECURITY_WEP_RX_ENABLE_SHIFT);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302706 security &= ~SECURITY_ENCRYP_MASK;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002707 security |= (SECURITY_ENCRYP_104<<SECURITY_ENCRYP_SHIFT);
2708
2709 write_nic_byte(dev, SECURITY, security);
2710
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302711 DMESG("key %x %x %x %x", read_nic_dword(dev, KEY0+4+4+4),
2712 read_nic_dword(dev, KEY0+4+4), read_nic_dword(dev, KEY0+4),
2713 read_nic_dword(dev, KEY0));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002714}
2715
2716
2717void rtl8185_rf_pins_enable(struct net_device *dev)
2718{
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302719 /* u16 tmp; */
2720 /* tmp = read_nic_word(dev, RFPinsEnable); */
2721 write_nic_word(dev, RFPinsEnable, 0x1fff); /* | tmp); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002722}
2723
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002724void rtl8185_set_anaparam2(struct net_device *dev, u32 a)
2725{
2726 u8 conf3;
2727
2728 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
2729
2730 conf3 = read_nic_byte(dev, CONFIG3);
2731 write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
2732 write_nic_dword(dev, ANAPARAM2, a);
2733
2734 conf3 = read_nic_byte(dev, CONFIG3);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302735 write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002736 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002737}
2738
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002739void rtl8180_set_anaparam(struct net_device *dev, u32 a)
2740{
2741 u8 conf3;
2742
2743 rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
2744
2745 conf3 = read_nic_byte(dev, CONFIG3);
2746 write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
2747 write_nic_dword(dev, ANAPARAM, a);
2748
2749 conf3 = read_nic_byte(dev, CONFIG3);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302750 write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002751 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
2752}
2753
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002754void rtl8185_tx_antenna(struct net_device *dev, u8 ant)
2755{
2756 write_nic_byte(dev, TX_ANTENNA, ant);
2757 force_pci_posting(dev);
2758 mdelay(1);
2759}
2760
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002761static void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002762{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002763 u32 phyw;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002764
2765 adr |= 0x80;
2766
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302767 phyw = ((data<<8) | adr);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002768
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302769 /* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002770 write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
2771 write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));
2772 write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302773 write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff)));
Bartlomiej Zolnierkiewicz5521a512009-06-28 16:19:23 +02002774
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002775 /* this is ok to fail when we write AGC table. check for AGC table might be
2776 * done by masking with 0x7f instead of 0xff
2777 */
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302778 /* if (phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002779}
2780
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302781inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002782{
2783 data = data & 0xff;
2784 rtl8185_write_phy(dev, adr, data);
2785}
2786
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302787void write_phy_cck(struct net_device *dev, u8 adr, u32 data)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002788{
2789 data = data & 0xff;
2790 rtl8185_write_phy(dev, adr, data | 0x10000);
2791}
2792
Andrew Millercd686802012-03-14 18:26:57 -04002793/*
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302794 * This configures registers for beacon tx and enables it via
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002795 * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might
2796 * be used to stop beacon transmission
2797 */
2798void rtl8180_start_tx_beacon(struct net_device *dev)
2799{
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002800 u16 word;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002801
2802 DMESG("Enabling beacon TX");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002803 rtl8180_prepare_beacon(dev);
2804 rtl8180_irq_disable(dev);
2805 rtl8180_beacon_tx_enable(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002806
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302807 word = read_nic_word(dev, AtimWnd) & ~AtimWnd_AtimWnd;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302808 write_nic_word(dev, AtimWnd, word); /* word |= */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002809
2810 word = read_nic_word(dev, BintrItv);
2811 word &= ~BintrItv_BintrItv;
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302812 word |= 1000; /* priv->ieee80211->current_network.beacon_interval *
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002813 ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1);
2814 // FIXME: check if correct ^^ worked with 0x3e8;
2815 */
2816 write_nic_word(dev, BintrItv, word);
2817
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002818 rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
2819
John Churchcb73da22010-04-08 16:04:17 -05002820 rtl8185b_irq_enable(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002821}
2822
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002823static struct net_device_stats *rtl8180_stats(struct net_device *dev)
2824{
2825 struct r8180_priv *priv = ieee80211_priv(dev);
2826
2827 return &priv->ieee80211->stats;
2828}
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302829
2830/*
2831 * Change current and default preamble mode.
2832 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002833bool
2834MgntActSet_802_11_PowerSaveMode(
2835 struct r8180_priv *priv,
2836 RT_PS_MODE rtPsMode
2837)
2838{
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302839 /* Currently, we do not change power save mode on IBSS mode. */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302840 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002841 return false;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002842
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002843 priv->ieee80211->ps = rtPsMode;
Bartlomiej Zolnierkiewicz5521a512009-06-28 16:19:23 +02002844
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002845 return true;
2846}
2847
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002848void LeisurePSEnter(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002849{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002850 if (priv->bLeisurePs) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002851 if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
Andrew Millerdec3a002012-03-14 18:26:59 -04002852 /* IEEE80211_PS_ENABLE */
2853 MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002854 }
2855}
2856
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002857void LeisurePSLeave(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002858{
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002859 if (priv->bLeisurePs) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002860 if (priv->ieee80211->ps != IEEE80211_PS_DISABLED)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002861 MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002862 }
2863}
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02002864
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302865void rtl8180_hw_wakeup_wq(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002866{
Jean Delvarebf6aede2009-04-02 16:56:54 -07002867 struct delayed_work *dwork = to_delayed_work(work);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302868 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_wakeup_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002869 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002870
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002871 rtl8180_hw_wakeup(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002872}
2873
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302874void rtl8180_hw_sleep_wq(struct work_struct *work)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002875{
Jean Delvarebf6aede2009-04-02 16:56:54 -07002876 struct delayed_work *dwork = to_delayed_work(work);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302877 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_sleep_wq);
John Churchcb73da22010-04-08 16:04:17 -05002878 struct net_device *dev = ieee->dev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002879
John Churchcb73da22010-04-08 16:04:17 -05002880 rtl8180_hw_sleep_down(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002881}
2882
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302883static void MgntLinkKeepAlive(struct r8180_priv *priv)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002884{
2885 if (priv->keepAliveLevel == 0)
2886 return;
2887
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302888 if (priv->ieee80211->state == IEEE80211_LINKED) {
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302889 /*
2890 * Keep-Alive.
2891 */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002892
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302893 if ((priv->keepAliveLevel == 2) ||
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002894 (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast &&
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302895 priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast)
2896 ) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002897 priv->link_detect.IdleCount++;
2898
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302899 /*
2900 * Send a Keep-Alive packet packet to AP if we had been idle for a while.
2901 */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302902 if (priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002903 priv->link_detect.IdleCount = 0;
2904 ieee80211_sta_ps_send_null_frame(priv->ieee80211, false);
2905 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302906 } else {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002907 priv->link_detect.IdleCount = 0;
2908 }
2909 priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast;
2910 priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast;
2911 }
2912}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002913
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002914void rtl8180_watch_dog(struct net_device *dev)
2915{
2916 struct r8180_priv *priv = ieee80211_priv(dev);
2917 bool bEnterPS = false;
2918 bool bBusyTraffic = false;
2919 u32 TotalRxNum = 0;
2920 u16 SlotIndex = 0;
2921 u16 i = 0;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302922 if (priv->ieee80211->actscanning == false) {
Andrew Millerdec3a002012-03-14 18:26:59 -04002923 if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) &&
2924 (priv->ieee80211->state == IEEE80211_NOLINK) &&
2925 (priv->ieee80211->beinretry == false) &&
2926 (priv->eRFPowerState == eRfOn))
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002927 IPSEnter(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002928 }
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302929 /* YJ,add,080828,for link state check */
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302930 if ((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002931 SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum;
2932 priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302933 for (i = 0; i < priv->link_detect.SlotNum; i++)
2934 TotalRxNum += priv->link_detect.RxFrameNum[i];
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002935
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302936 if (TotalRxNum == 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002937 priv->ieee80211->state = IEEE80211_ASSOCIATING;
2938 queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq);
2939 }
2940 }
2941
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302942 /* YJ,add,080828,for KeepAlive */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002943 MgntLinkKeepAlive(priv);
2944
Prashant P. Shah3f56c102010-05-13 23:09:08 +05302945 /* YJ,add,080828,for LPS */
Maxim Mikityanskiy53094af2012-11-13 19:28:23 +02002946 LeisurePSLeave(priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002947
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302948 if (priv->ieee80211->state == IEEE80211_LINKED) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002949 priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302950 if (priv->link_detect.NumRxOkInPeriod > 666 ||
2951 priv->link_detect.NumTxOkInPeriod > 666) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002952 bBusyTraffic = true;
2953 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302954 if (((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002955 || (priv->link_detect.NumRxOkInPeriod > 2)) {
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302956 bEnterPS = false;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002957 } else
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302958 bEnterPS = true;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002959
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002960 if (bEnterPS)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002961 LeisurePSEnter(priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002962 else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002963 LeisurePSLeave(priv);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002964 } else
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002965 LeisurePSLeave(priv);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002966 priv->link_detect.bBusyTraffic = bBusyTraffic;
2967 priv->link_detect.NumRxOkInPeriod = 0;
2968 priv->link_detect.NumTxOkInPeriod = 0;
2969 priv->ieee80211->NumRxDataInPeriod = 0;
2970 priv->ieee80211->NumRxBcnInPeriod = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002971}
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02002972
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002973static int _rtl8180_up(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002974{
2975 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002976
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302977 priv->up = 1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002978
2979 DMESG("Bringing up iface");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002980 rtl8185b_adapter_start(dev);
2981 rtl8185b_rx_enable(dev);
2982 rtl8185b_tx_enable(dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302983 if (priv->bInactivePs) {
2984 if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002985 IPSLeave(dev);
2986 }
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05302987 timer_rate_adaptive((unsigned long)dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002988 watch_dog_adaptive((unsigned long)dev);
John Churchcb73da22010-04-08 16:04:17 -05002989 if (priv->bSwAntennaDiverity)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002990 SwAntennaDiversityTimerCallback(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002991 ieee80211_softmac_start_protocol(priv->ieee80211);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002992 return 0;
2993}
2994
Teodora Baluta17ab33e2013-10-19 21:09:47 +03002995static int rtl8180_open(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08002996{
2997 struct r8180_priv *priv = ieee80211_priv(dev);
2998 int ret;
2999
3000 down(&priv->wx_sem);
3001 ret = rtl8180_up(dev);
3002 up(&priv->wx_sem);
3003 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003004}
3005
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003006int rtl8180_up(struct net_device *dev)
3007{
3008 struct r8180_priv *priv = ieee80211_priv(dev);
3009
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303010 if (priv->up == 1)
3011 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003012
3013 return _rtl8180_up(dev);
3014}
3015
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003016static int rtl8180_close(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003017{
3018 struct r8180_priv *priv = ieee80211_priv(dev);
3019 int ret;
3020
3021 down(&priv->wx_sem);
3022 ret = rtl8180_down(dev);
3023 up(&priv->wx_sem);
3024
3025 return ret;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003026}
3027
3028int rtl8180_down(struct net_device *dev)
3029{
3030 struct r8180_priv *priv = ieee80211_priv(dev);
3031
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003032 if (priv->up == 0)
3033 return -1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003034
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303035 priv->up = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003036
3037 ieee80211_softmac_stop_protocol(priv->ieee80211);
3038 /* FIXME */
3039 if (!netif_queue_stopped(dev))
3040 netif_stop_queue(dev);
3041 rtl8180_rtx_disable(dev);
3042 rtl8180_irq_disable(dev);
3043 del_timer_sync(&priv->watch_dog_timer);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003044 del_timer_sync(&priv->rateadapter_timer);
3045 cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003046 cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
3047 cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
3048 cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
3049 cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
3050 del_timer_sync(&priv->SwAntennaDiversityTimer);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303051 SetZebraRFPowerState8185(dev, eRfOff);
3052 memset(&(priv->ieee80211->current_network), 0, sizeof(struct ieee80211_network));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003053 priv->ieee80211->state = IEEE80211_NOLINK;
3054 return 0;
3055}
3056
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003057void rtl8180_restart_wq(struct work_struct *work)
3058{
3059 struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
3060 struct net_device *dev = priv->dev;
Bartlomiej Zolnierkiewicz03704532009-06-13 18:30:28 +02003061
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003062 down(&priv->wx_sem);
3063
3064 rtl8180_commit(dev);
3065
3066 up(&priv->wx_sem);
3067}
3068
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003069static void rtl8180_restart(struct net_device *dev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003070{
3071 struct r8180_priv *priv = ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003072
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003073 schedule_work(&priv->reset_wq);
3074}
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003075
3076void rtl8180_commit(struct net_device *dev)
3077{
3078 struct r8180_priv *priv = ieee80211_priv(dev);
3079
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003080 if (priv->up == 0)
3081 return ;
3082
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003083 del_timer_sync(&priv->watch_dog_timer);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003084 del_timer_sync(&priv->rateadapter_timer);
3085 cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003086 cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
3087 cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
3088 cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
3089 cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
3090 del_timer_sync(&priv->SwAntennaDiversityTimer);
3091 ieee80211_softmac_stop_protocol(priv->ieee80211);
3092 rtl8180_irq_disable(dev);
3093 rtl8180_rtx_disable(dev);
3094 _rtl8180_up(dev);
3095}
3096
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003097static void r8180_set_multicast(struct net_device *dev)
3098{
3099 struct r8180_priv *priv = ieee80211_priv(dev);
3100 short promisc;
3101
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303102 promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003103
3104 if (promisc != priv->promisc)
3105 rtl8180_restart(dev);
3106
3107 priv->promisc = promisc;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003108}
3109
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003110static int r8180_set_mac_adr(struct net_device *dev, void *mac)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003111{
3112 struct r8180_priv *priv = ieee80211_priv(dev);
3113 struct sockaddr *addr = mac;
3114
3115 down(&priv->wx_sem);
3116
3117 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
3118
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303119 if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003120 memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN);
3121
3122 if (priv->up) {
3123 rtl8180_down(dev);
3124 rtl8180_up(dev);
3125 }
3126
3127 up(&priv->wx_sem);
3128
3129 return 0;
3130}
3131
3132/* based on ipw2200 driver */
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003133static int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003134{
3135 struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003136 struct iwreq *wrq = (struct iwreq *) rq;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303137 int ret = -1;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003138
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003139 switch (cmd) {
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003140 case RTL_IOCTL_WPA_SUPPLICANT:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003141 ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data);
3142 return ret;
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003143 default:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003144 return -EOPNOTSUPP;
3145 }
3146
3147 return -EOPNOTSUPP;
3148}
3149
Alexander Beregalov727ae302009-05-10 03:06:54 +04003150static const struct net_device_ops rtl8180_netdev_ops = {
3151 .ndo_open = rtl8180_open,
3152 .ndo_stop = rtl8180_close,
3153 .ndo_get_stats = rtl8180_stats,
3154 .ndo_tx_timeout = rtl8180_restart,
3155 .ndo_do_ioctl = rtl8180_ioctl,
Jiri Pirkoafc4b132011-08-16 06:29:01 +00003156 .ndo_set_rx_mode = r8180_set_multicast,
Alexander Beregalov727ae302009-05-10 03:06:54 +04003157 .ndo_set_mac_address = r8180_set_mac_adr,
3158 .ndo_validate_addr = eth_validate_addr,
3159 .ndo_change_mtu = eth_change_mtu,
George Kadianakisdf574b82009-12-17 01:16:00 +02003160 .ndo_start_xmit = ieee80211_rtl_xmit,
Alexander Beregalov727ae302009-05-10 03:06:54 +04003161};
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003162
Bill Pemberton19fc6b52012-11-19 13:22:08 -05003163static int rtl8180_pci_probe(struct pci_dev *pdev,
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003164 const struct pci_device_id *id)
3165{
3166 unsigned long ioaddr = 0;
3167 struct net_device *dev = NULL;
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303168 struct r8180_priv *priv = NULL;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003169 u8 unit = 0;
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003170 int ret = -ENODEV;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003171
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003172 unsigned long pmem_start, pmem_len, pmem_flags;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003173
3174 DMESG("Configuring chip resources");
3175
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303176 if (pci_enable_device(pdev)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003177 DMESG("Failed to enable PCI device");
3178 return -EIO;
3179 }
3180
3181 pci_set_master(pdev);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003182 pci_set_dma_mask(pdev, 0xffffff00ULL);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303183 pci_set_consistent_dma_mask(pdev, 0xffffff00ULL);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003184 dev = alloc_ieee80211(sizeof(struct r8180_priv));
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003185 if (!dev) {
3186 ret = -ENOMEM;
3187 goto fail_free;
3188 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003189 priv = ieee80211_priv(dev);
3190 priv->ieee80211 = netdev_priv(dev);
3191
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003192 pci_set_drvdata(pdev, dev);
3193 SET_NETDEV_DEV(dev, &pdev->dev);
3194
3195 priv = ieee80211_priv(dev);
Bartlomiej Zolnierkiewiczfd882782009-06-28 16:20:38 +02003196 priv->pdev = pdev;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003197
3198 pmem_start = pci_resource_start(pdev, 1);
3199 pmem_len = pci_resource_len(pdev, 1);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303200 pmem_flags = pci_resource_flags(pdev, 1);
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003201
3202 if (!(pmem_flags & IORESOURCE_MEM)) {
3203 DMESG("region #1 not a MMIO resource, aborting");
3204 goto fail;
3205 }
3206
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303207 if (!request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003208 DMESG("request_mem_region failed!");
3209 goto fail;
3210 }
3211
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303212 ioaddr = (unsigned long)ioremap_nocache(pmem_start, pmem_len);
3213 if (ioaddr == (unsigned long)NULL) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003214 DMESG("ioremap failed!");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003215 goto fail1;
3216 }
3217
Prashant P. Shah3f56c102010-05-13 23:09:08 +05303218 dev->mem_start = ioaddr; /* shared mem start */
3219 dev->mem_end = ioaddr + pci_resource_len(pdev, 0); /* shared mem end */
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003220
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003221 pci_read_config_byte(pdev, 0x05, &unit);
3222 pci_write_config_byte(pdev, 0x05, unit & (~0x04));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003223
3224 dev->irq = pdev->irq;
3225 priv->irq = 0;
3226
Alexander Beregalov727ae302009-05-10 03:06:54 +04003227 dev->netdev_ops = &rtl8180_netdev_ops;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003228 dev->wireless_handlers = &r8180_wx_handlers_def;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003229
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303230 dev->type = ARPHRD_ETHER;
Larry Finger19941302010-01-25 13:11:49 -06003231 dev->watchdog_timeo = HZ*3;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003232
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303233 if (dev_alloc_name(dev, ifname) < 0) {
John Churchcb73da22010-04-08 16:04:17 -05003234 DMESG("Oops: devname already taken! Trying wlan%%d...\n");
Rusty Russelldca41302010-08-11 23:04:21 -06003235 strcpy(ifname, "wlan%d");
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003236 dev_alloc_name(dev, ifname);
John Churchcb73da22010-04-08 16:04:17 -05003237 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003238
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303239 if (rtl8180_init(dev) != 0) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003240 DMESG("Initialization failed");
3241 goto fail1;
3242 }
3243
3244 netif_carrier_off(dev);
3245
Kumar Amit Mehta36e97a52012-11-14 15:30:57 +05303246 if (register_netdev(dev))
3247 goto fail1;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003248
3249 rtl8180_proc_init_one(dev);
3250
3251 DMESG("Driver probe completed\n");
3252 return 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003253fail1:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303254 if (dev->mem_start != (unsigned long)NULL) {
Teodora Baluta8e87b1b2013-10-19 21:09:46 +03003255 iounmap((void __iomem *)dev->mem_start);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303256 release_mem_region(pci_resource_start(pdev, 1),
3257 pci_resource_len(pdev, 1));
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003258 }
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003259fail:
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303260 if (dev) {
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003261 if (priv->irq) {
3262 free_irq(dev->irq, dev);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303263 dev->irq = 0;
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003264 }
3265 free_ieee80211(dev);
3266 }
3267
Kulikov Vasiliybeef9692010-08-09 23:51:52 +04003268fail_free:
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003269 pci_disable_device(pdev);
3270
3271 DMESG("wlan driver load failed\n");
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) {
Teodora Baluta8e87b1b2013-10-19 21:09:46 +03003301 iounmap((void __iomem *)dev->mem_start);
Prashant P. Shahbbfb5652010-05-13 23:08:43 +05303302 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
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003372static void rtl8180_try_wake_queue(struct net_device *dev, int pri)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003373{
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
Teodora Baluta17ab33e2013-10-19 21:09:47 +03003386static void 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
navin patidar9fc09442013-08-23 18:24:02 +05303540irqreturn_t rtl8180_interrupt(int irq, void *netdev)
Greg Kroah-Hartmanc8d86be2008-12-04 20:01:41 -08003541{
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);