blob: 76a67386b927326e99c793059ce3093d07e52b63 [file] [log] [blame]
/*
This is part of rtl818x pci OpenSource driver - v 0.1
Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
Released under the terms of GPL (General Public License)
Parts of this driver are based on the GPL part of the official
Realtek driver.
Parts of this driver are based on the rtl8180 driver skeleton
from Patric Schenke & Andres Salomon.
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
Parts of BB/RF code are derived from David Young rtl8180 netbsd driver.
RSSI calc function from 'The Deuce'
Some ideas borrowed from the 8139too.c driver included in linux kernel.
We (I?) want to thanks the Authors of those projecs and also the
Ndiswrapper's project Authors.
A big big thanks goes also to Realtek corp. for their help in my attempt to
add RTL8185 and RTL8225 support, and to David Young also.
Power management interface routines.
Written by Mariusz Matuszek.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#undef RX_DONT_PASS_UL
#undef DUMMY_RX
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/eeprom_93cx6.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "r8180_hw.h"
#include "r8180.h"
#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
#include "r8180_93cx6.h" /* Card EEPROM */
#include "r8180_wx.h"
#include "r8180_dm.h"
#include "ieee80211/dot11d.h"
static struct pci_device_id rtl8180_pci_id_tbl[] = {
{
.vendor = PCI_VENDOR_ID_REALTEK,
.device = 0x8199,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = 0,
},
{
.vendor = 0,
.device = 0,
.subvendor = 0,
.subdevice = 0,
.driver_data = 0,
}
};
static char ifname[IFNAMSIZ] = "wlan%d";
static int hwwep;
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards");
module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
module_param(hwwep, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support. Still broken and not available on all cards");
static int rtl8180_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void rtl8180_pci_remove(struct pci_dev *pdev);
static void rtl8180_shutdown(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (dev->netdev_ops->ndo_stop)
dev->netdev_ops->ndo_stop(dev);
pci_disable_device(pdev);
}
static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (!netif_running(dev))
goto out_pci_suspend;
if (dev->netdev_ops->ndo_stop)
dev->netdev_ops->ndo_stop(dev);
netif_device_detach(dev);
out_pci_suspend:
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
static int rtl8180_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
int err;
u32 val;
pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "pci_enable_device failed on resume\n");
return err;
}
pci_restore_state(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
* from interfering with C3 CPU state. pci_restore_state won't help
* here since it only restores the first 64 bytes pci config header.
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
if (!netif_running(dev))
goto out;
if (dev->netdev_ops->ndo_open)
dev->netdev_ops->ndo_open(dev);
netif_device_attach(dev);
out:
return 0;
}
static struct pci_driver rtl8180_pci_driver = {
.name = RTL8180_MODULE_NAME,
.id_table = rtl8180_pci_id_tbl,
.probe = rtl8180_pci_probe,
.remove = rtl8180_pci_remove,
.suspend = rtl8180_suspend,
.resume = rtl8180_resume,
.shutdown = rtl8180_shutdown,
};
u8 read_nic_byte(struct net_device *dev, int x)
{
return 0xff&readb((u8 __iomem *)dev->mem_start + x);
}
u32 read_nic_dword(struct net_device *dev, int x)
{
return readl((u8 __iomem *)dev->mem_start + x);
}
u16 read_nic_word(struct net_device *dev, int x)
{
return readw((u8 __iomem *)dev->mem_start + x);
}
void write_nic_byte(struct net_device *dev, int x, u8 y)
{
writeb(y, (u8 __iomem *)dev->mem_start + x);
udelay(20);
}
void write_nic_dword(struct net_device *dev, int x, u32 y)
{
writel(y, (u8 __iomem *)dev->mem_start + x);
udelay(20);
}
void write_nic_word(struct net_device *dev, int x, u16 y)
{
writew(y, (u8 __iomem *)dev->mem_start + x);
udelay(20);
}
inline void force_pci_posting(struct net_device *dev)
{
read_nic_byte(dev, EPROM_CMD);
mb();
}
static irqreturn_t rtl8180_interrupt(int irq, void *netdev);
void set_nic_rxring(struct net_device *dev);
void set_nic_txring(struct net_device *dev);
static struct net_device_stats *rtl8180_stats(struct net_device *dev);
void rtl8180_commit(struct net_device *dev);
void rtl8180_start_tx_beacon(struct net_device *dev);
static struct proc_dir_entry *rtl8180_proc;
static int proc_get_registers(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
int i, n, max = 0xff;
/* This dump the current register page */
for (n = 0; n <= max;) {
seq_printf(m, "\nD: %2x > ", n);
for (i = 0; i < 16 && n <= max; i++, n++)
seq_printf(m, "%2x ", read_nic_byte(dev, n));
}
seq_putc(m, '\n');
return 0;
}
int get_curr_tx_free_desc(struct net_device *dev, int priority);
static int proc_get_stats_hw(struct seq_file *m, void *v)
{
return 0;
}
static int proc_get_stats_rx(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
seq_printf(m,
"RX OK: %lu\n"
"RX Retry: %lu\n"
"RX CRC Error(0-500): %lu\n"
"RX CRC Error(500-1000): %lu\n"
"RX CRC Error(>1000): %lu\n"
"RX ICV Error: %lu\n",
priv->stats.rxint,
priv->stats.rxerr,
priv->stats.rxcrcerrmin,
priv->stats.rxcrcerrmid,
priv->stats.rxcrcerrmax,
priv->stats.rxicverr
);
return 0;
}
static int proc_get_stats_tx(struct seq_file *m, void *v)
{
struct net_device *dev = m->private;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
unsigned long totalOK;
totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
seq_printf(m,
"TX OK: %lu\n"
"TX Error: %lu\n"
"TX Retry: %lu\n"
"TX beacon OK: %lu\n"
"TX beacon error: %lu\n",
totalOK,
priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr,
priv->stats.txretry,
priv->stats.txbeacon,
priv->stats.txbeaconerr
);
return 0;
}
static void rtl8180_proc_module_init(void)
{
DMESG("Initializing proc filesystem");
rtl8180_proc = proc_mkdir(RTL8180_MODULE_NAME, init_net.proc_net);
}
static void rtl8180_proc_module_remove(void)
{
remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net);
}
static void rtl8180_proc_remove_one(struct net_device *dev)
{
remove_proc_subtree(dev->name, rtl8180_proc);
}
/*
* seq_file wrappers for procfile show routines.
*/
static int rtl8180_proc_open(struct inode *inode, struct file *file)
{
struct net_device *dev = proc_get_parent_data(inode);
int (*show)(struct seq_file *, void *) = PDE_DATA(inode);
return single_open(file, show, dev);
}
static const struct file_operations rtl8180_proc_fops = {
.open = rtl8180_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* Table of proc files we need to create.
*/
struct rtl8180_proc_file {
char name[12];
int (*show)(struct seq_file *, void *);
};
static const struct rtl8180_proc_file rtl8180_proc_files[] = {
{ "stats-hw", &proc_get_stats_hw },
{ "stats-rx", &proc_get_stats_rx },
{ "stats-tx", &proc_get_stats_tx },
{ "registers", &proc_get_registers },
{ "" }
};
static void rtl8180_proc_init_one(struct net_device *dev)
{
const struct rtl8180_proc_file *f;
struct proc_dir_entry *dir;
dir = proc_mkdir_data(dev->name, 0, rtl8180_proc, dev);
if (!dir) {
DMESGE("Unable to initialize /proc/net/r8180/%s\n", dev->name);
return;
}
for (f = rtl8180_proc_files; f->name[0]; f++) {
if (!proc_create_data(f->name, S_IFREG | S_IRUGO, dir,
&rtl8180_proc_fops, f->show)) {
DMESGE("Unable to initialize /proc/net/r8180/%s/%s\n",
dev->name, f->name);
return;
}
}
}
/*
FIXME: check if we can use some standard already-existent
data type+functions in kernel
*/
static short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma,
struct buffer **bufferhead)
{
struct buffer *tmp;
if (!*buffer) {
*buffer = kmalloc(sizeof(struct buffer), GFP_KERNEL);
if (*buffer == NULL) {
DMESGE("Failed to kmalloc head of TX/RX struct");
return -1;
}
(*buffer)->next = *buffer;
(*buffer)->buf = buf;
(*buffer)->dma = dma;
if (bufferhead != NULL)
(*bufferhead) = (*buffer);
return 0;
}
tmp = *buffer;
while (tmp->next != (*buffer))
tmp = tmp->next;
tmp->next = kmalloc(sizeof(struct buffer), GFP_KERNEL);
if (tmp->next == NULL) {
DMESGE("Failed to kmalloc TX/RX struct");
return -1;
}
tmp->next->buf = buf;
tmp->next->dma = dma;
tmp->next->next = *buffer;
return 0;
}
void buffer_free(struct net_device *dev, struct buffer **buffer, int len, short consistent)
{
struct buffer *tmp, *next;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
if (!*buffer)
return;
tmp = *buffer;
do {
next = tmp->next;
if (consistent) {
pci_free_consistent(pdev, len,
tmp->buf, tmp->dma);
} else {
pci_unmap_single(pdev, tmp->dma,
len, PCI_DMA_FROMDEVICE);
kfree(tmp->buf);
}
kfree(tmp);
tmp = next;
} while (next != *buffer);
*buffer = NULL;
}
int get_curr_tx_free_desc(struct net_device *dev, int priority)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *tail;
u32 *head;
int ret;
switch (priority) {
case MANAGE_PRIORITY:
head = priv->txmapringhead;
tail = priv->txmapringtail;
break;
case BK_PRIORITY:
head = priv->txbkpringhead;
tail = priv->txbkpringtail;
break;
case BE_PRIORITY:
head = priv->txbepringhead;
tail = priv->txbepringtail;
break;
case VI_PRIORITY:
head = priv->txvipringhead;
tail = priv->txvipringtail;
break;
case VO_PRIORITY:
head = priv->txvopringhead;
tail = priv->txvopringtail;
break;
case HI_PRIORITY:
head = priv->txhpringhead;
tail = priv->txhpringtail;
break;
default:
return -1;
}
if (head <= tail)
ret = priv->txringcount - (tail - head)/8;
else
ret = (head - tail)/8;
if (ret > priv->txringcount)
DMESG("BUG");
return ret;
}
static short check_nic_enought_desc(struct net_device *dev, int priority)
{
struct r8180_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = netdev_priv(dev);
int requiredbyte, required;
requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
if (ieee->current_network.QoS_Enable)
requiredbyte += 2;
required = requiredbyte / (priv->txbuffsize-4);
if (requiredbyte % priv->txbuffsize)
required++;
/* for now we keep two free descriptor as a safety boundary
* between the tail and the head
*/
return (required+2 < get_curr_tx_free_desc(dev, priority));
}
void fix_tx_fifo(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 *tmp;
int i;
for (tmp = priv->txmapring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbkpring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbepring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txvipring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txvopring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txhpring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbeaconring, i = 0;
i < priv->txbeaconcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
priv->txmapringtail = priv->txmapring;
priv->txmapringhead = priv->txmapring;
priv->txmapbufstail = priv->txmapbufs;
priv->txbkpringtail = priv->txbkpring;
priv->txbkpringhead = priv->txbkpring;
priv->txbkpbufstail = priv->txbkpbufs;
priv->txbepringtail = priv->txbepring;
priv->txbepringhead = priv->txbepring;
priv->txbepbufstail = priv->txbepbufs;
priv->txvipringtail = priv->txvipring;
priv->txvipringhead = priv->txvipring;
priv->txvipbufstail = priv->txvipbufs;
priv->txvopringtail = priv->txvopring;
priv->txvopringhead = priv->txvopring;
priv->txvopbufstail = priv->txvopbufs;
priv->txhpringtail = priv->txhpring;
priv->txhpringhead = priv->txhpring;
priv->txhpbufstail = priv->txhpbufs;
priv->txbeaconringtail = priv->txbeaconring;
priv->txbeaconbufstail = priv->txbeaconbufs;
set_nic_txring(dev);
ieee80211_reset_queue(priv->ieee80211);
priv->ack_tx_to_ieee = 0;
}
void fix_rx_fifo(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 *tmp;
struct buffer *rxbuf;
u8 rx_desc_size;
rx_desc_size = 8; /* 4*8 = 32 bytes */
for (tmp = priv->rxring, rxbuf = priv->rxbufferhead;
(tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size);
tmp += rx_desc_size, rxbuf = rxbuf->next) {
*(tmp+2) = rxbuf->dma;
*tmp = *tmp & ~0xfff;
*tmp = *tmp | priv->rxbuffersize;
*tmp |= (1<<31);
}
priv->rxringtail = priv->rxring;
priv->rxbuffer = priv->rxbufferhead;
priv->rx_skb_complete = 1;
set_nic_rxring(dev);
}
static void rtl8180_irq_disable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, IMR, 0);
force_pci_posting(dev);
priv->irq_enabled = 0;
}
void rtl8180_set_mode(struct net_device *dev, int mode)
{
u8 ecmd;
ecmd = read_nic_byte(dev, EPROM_CMD);
ecmd = ecmd & ~EPROM_CMD_OPERATING_MODE_MASK;
ecmd = ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT);
ecmd = ecmd & ~(1<<EPROM_CS_SHIFT);
ecmd = ecmd & ~(1<<EPROM_CK_SHIFT);
write_nic_byte(dev, EPROM_CMD, ecmd);
}
void rtl8180_beacon_tx_enable(struct net_device *dev);
void rtl8180_update_msr(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 msr;
u32 rxconf;
msr = read_nic_byte(dev, MSR);
msr &= ~MSR_LINK_MASK;
rxconf = read_nic_dword(dev, RX_CONF);
if (priv->ieee80211->state == IEEE80211_LINKED) {
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT);
else if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT);
else if (priv->ieee80211->iw_mode == IW_MODE_INFRA)
msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT);
else
msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
rxconf |= (1<<RX_CHECK_BSSID_SHIFT);
} else {
msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
rxconf &= ~(1<<RX_CHECK_BSSID_SHIFT);
}
write_nic_byte(dev, MSR, msr);
write_nic_dword(dev, RX_CONF, rxconf);
}
void rtl8180_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
if ((ch > 14) || (ch < 1)) {
printk("In %s: Invalid chnanel %d\n", __func__, ch);
return;
}
priv->chan = ch;
priv->rf_set_chan(dev, priv->chan);
}
void set_nic_txring(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma);
write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma);
write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma);
write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma);
write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma);
write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma);
write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma);
}
void rtl8180_beacon_tx_enable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);
write_nic_byte(dev, TPPollStop, priv->dma_poll_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
void rtl8180_beacon_tx_disable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ;
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
void rtl8180_rtx_disable(struct net_device *dev)
{
u8 cmd;
struct r8180_priv *priv = ieee80211_priv(dev);
cmd = read_nic_byte(dev, CMD);
write_nic_byte(dev, CMD, cmd &
~((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT)));
force_pci_posting(dev);
mdelay(10);
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
}
static short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
int addr)
{
int i;
u32 *desc;
u32 *tmp;
dma_addr_t dma_desc, dma_tmp;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
void *buf;
if ((bufsize & 0xfff) != bufsize) {
DMESGE("TX buffer allocation too large");
return 0;
}
desc = (u32 *)pci_alloc_consistent(pdev,
sizeof(u32)*8*count+256, &dma_desc);
if (desc == NULL)
return -1;
if (dma_desc & 0xff)
/*
* descriptor's buffer must be 256 byte aligned
* we shouldn't be here, since we set DMA mask !
*/
WARN(1, "DMA buffer is not aligned\n");
tmp = desc;
for (i = 0; i < count; i++) {
buf = (void *)pci_alloc_consistent(pdev, bufsize, &dma_tmp);
if (buf == NULL)
return -ENOMEM;
switch (addr) {
case TX_MANAGEPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_BKPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_BEPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_VIPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_VOPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_HIGHPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer HP");
return -ENOMEM;
}
break;
case TX_BEACON_RING_ADDR:
if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer BP");
return -ENOMEM;
}
break;
}
*tmp = *tmp & ~(1<<31); /* descriptor empty, owned by the drv */
*(tmp+2) = (u32)dma_tmp;
*(tmp+3) = bufsize;
if (i+1 < count)
*(tmp+4) = (u32)dma_desc+((i+1)*8*4);
else
*(tmp+4) = (u32)dma_desc;
tmp = tmp+8;
}
switch (addr) {
case TX_MANAGEPRIORITY_RING_ADDR:
priv->txmapringdma = dma_desc;
priv->txmapring = desc;
break;
case TX_BKPRIORITY_RING_ADDR:
priv->txbkpringdma = dma_desc;
priv->txbkpring = desc;
break;
case TX_BEPRIORITY_RING_ADDR:
priv->txbepringdma = dma_desc;
priv->txbepring = desc;
break;
case TX_VIPRIORITY_RING_ADDR:
priv->txvipringdma = dma_desc;
priv->txvipring = desc;
break;
case TX_VOPRIORITY_RING_ADDR:
priv->txvopringdma = dma_desc;
priv->txvopring = desc;
break;
case TX_HIGHPRIORITY_RING_ADDR:
priv->txhpringdma = dma_desc;
priv->txhpring = desc;
break;
case TX_BEACON_RING_ADDR:
priv->txbeaconringdma = dma_desc;
priv->txbeaconring = desc;
break;
}
return 0;
}
static void free_tx_desc_rings(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
int count = priv->txringcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txmapring, priv->txmapringdma);
buffer_free(dev, &(priv->txmapbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbkpring, priv->txbkpringdma);
buffer_free(dev, &(priv->txbkpbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbepring, priv->txbepringdma);
buffer_free(dev, &(priv->txbepbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txvipring, priv->txvipringdma);
buffer_free(dev, &(priv->txvipbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txvopring, priv->txvopringdma);
buffer_free(dev, &(priv->txvopbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txhpring, priv->txhpringdma);
buffer_free(dev, &(priv->txhpbufs), priv->txbuffsize, 1);
count = priv->txbeaconcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbeaconring, priv->txbeaconringdma);
buffer_free(dev, &(priv->txbeaconbufs), priv->txbuffsize, 1);
}
static void free_rx_desc_ring(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
int count = priv->rxringcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->rxring, priv->rxringdma);
buffer_free(dev, &(priv->rxbuffer), priv->rxbuffersize, 0);
}
static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
{
int i;
u32 *desc;
u32 *tmp;
dma_addr_t dma_desc, dma_tmp;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
void *buf;
u8 rx_desc_size;
rx_desc_size = 8; /* 4*8 = 32 bytes */
if ((bufsize & 0xfff) != bufsize) {
DMESGE("RX buffer allocation too large");
return -1;
}
desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256,
&dma_desc);
if (dma_desc & 0xff)
/*
* descriptor's buffer must be 256 byte aligned
* should never happen since we specify the DMA mask
*/
WARN(1, "DMA buffer is not aligned\n");
priv->rxring = desc;
priv->rxringdma = dma_desc;
tmp = desc;
for (i = 0; i < count; i++) {
buf = kmalloc(bufsize * sizeof(u8), GFP_ATOMIC);
if (buf == NULL) {
DMESGE("Failed to kmalloc RX buffer");
return -1;
}
dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8),
PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(pdev, dma_tmp))
return -1;
if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp,
&(priv->rxbufferhead))) {
DMESGE("Unable to allocate mem RX buf");
return -1;
}
*tmp = 0; /* zero pads the header of the descriptor */
*tmp = *tmp | (bufsize&0xfff);
*(tmp+2) = (u32)dma_tmp;
*tmp = *tmp | (1<<31); /* descriptor void, owned by the NIC */
tmp = tmp+rx_desc_size;
}
*(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */
return 0;
}
void set_nic_rxring(struct net_device *dev)
{
u8 pgreg;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
pgreg = read_nic_byte(dev, PGSELECT);
write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
write_nic_dword(dev, RXRING_ADDR, priv->rxringdma);
}
void rtl8180_reset(struct net_device *dev)
{
u8 cr;
rtl8180_irq_disable(dev);
cr = read_nic_byte(dev, CMD);
cr = cr & 2;
cr = cr | (1<<CMD_RST_SHIFT);
write_nic_byte(dev, CMD, cr);
force_pci_posting(dev);
mdelay(200);
if (read_nic_byte(dev, CMD) & (1<<CMD_RST_SHIFT))
DMESGW("Card reset timeout!");
else
DMESG("Card successfully reset");
rtl8180_set_mode(dev, EPROM_CMD_LOAD);
force_pci_posting(dev);
mdelay(200);
}
inline u16 ieeerate2rtlrate(int rate)
{
switch (rate) {
case 10:
return 0;
case 20:
return 1;
case 55:
return 2;
case 110:
return 3;
case 60:
return 4;
case 90:
return 5;
case 120:
return 6;
case 180:
return 7;
case 240:
return 8;
case 360:
return 9;
case 480:
return 10;
case 540:
return 11;
default:
return 3;
}
}
static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720};
inline u16 rtl8180_rate2rate(short rate)
{
if (rate > 12)
return 10;
return rtl_rate[rate];
}
inline u8 rtl8180_IsWirelessBMode(u16 rate)
{
if (((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220))
return 1;
else
return 0;
}
u16 N_DBPSOfRate(u16 DataRate);
u16 ComputeTxTime(u16 FrameLength, u16 DataRate, u8 bManagementFrame,
u8 bShortPreamble)
{
u16 FrameTime;
u16 N_DBPS;
u16 Ceiling;
if (rtl8180_IsWirelessBMode(DataRate)) {
if (bManagementFrame || !bShortPreamble || DataRate == 10)
/* long preamble */
FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10)));
else
/* short preamble */
FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10)));
if ((FrameLength*8 % (DataRate/10)) != 0) /* get the ceilling */
FrameTime++;
} else { /* 802.11g DSSS-OFDM PLCP length field calculation. */
N_DBPS = N_DBPSOfRate(DataRate);
Ceiling = (16 + 8*FrameLength + 6) / N_DBPS
+ (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0);
FrameTime = (u16)(16 + 4 + 4*Ceiling + 6);
}
return FrameTime;
}
u16 N_DBPSOfRate(u16 DataRate)
{
u16 N_DBPS = 24;
switch (DataRate) {
case 60:
N_DBPS = 24;
break;
case 90:
N_DBPS = 36;
break;
case 120:
N_DBPS = 48;
break;
case 180:
N_DBPS = 72;
break;
case 240:
N_DBPS = 96;
break;
case 360:
N_DBPS = 144;
break;
case 480:
N_DBPS = 192;
break;
case 540:
N_DBPS = 216;
break;
default:
break;
}
return N_DBPS;
}
/*
* For Netgear case, they want good-looking signal strength.
*/
static long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
{
long RetSS;
/* Step 1. Scale mapping. */
if (CurrSS >= 71 && CurrSS <= 100)
RetSS = 90 + ((CurrSS - 70) / 3);
else if (CurrSS >= 41 && CurrSS <= 70)
RetSS = 78 + ((CurrSS - 40) / 3);
else if (CurrSS >= 31 && CurrSS <= 40)
RetSS = 66 + (CurrSS - 30);
else if (CurrSS >= 21 && CurrSS <= 30)
RetSS = 54 + (CurrSS - 20);
else if (CurrSS >= 5 && CurrSS <= 20)
RetSS = 42 + (((CurrSS - 5) * 2) / 3);
else if (CurrSS == 4)
RetSS = 36;
else if (CurrSS == 3)
RetSS = 27;
else if (CurrSS == 2)
RetSS = 18;
else if (CurrSS == 1)
RetSS = 9;
else
RetSS = CurrSS;
/* Step 2. Smoothing. */
if (LastSS > 0)
RetSS = ((LastSS * 5) + (RetSS) + 5) / 6;
return RetSS;
}
/*
* Translate 0-100 signal strength index into dBm.
*/
static long TranslateToDbm8185(u8 SignalStrengthIndex)
{
long SignalPower;
/* Translate to dBm (x=0.5y-95). */
SignalPower = (long)((SignalStrengthIndex + 1) >> 1);
SignalPower -= 95;
return SignalPower;
}
/*
* Perform signal smoothing for dynamic mechanism.
* This is different with PerformSignalSmoothing8185 in smoothing formula.
* No dramatic adjustion is apply because dynamic mechanism need some degree
* of correctness. Ported from 8187B.
*/
static void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
bool bCckRate)
{
/* Determin the current packet is CCK rate. */
priv->bCurCCKPkt = bCckRate;
if (priv->UndecoratedSmoothedSS >= 0)
priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
(priv->SignalStrength * 10)) / 6;
else
priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) +
(priv->RxPower * 11)) / 60;
if (bCckRate)
priv->CurCCKRSSI = priv->RSSI;
else
priv->CurCCKRSSI = 0;
}
/*
* This is rough RX isr handling routine
*/
static void rtl8180_rx(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct sk_buff *tmp_skb;
short first, last;
u32 len;
int lastlen;
unsigned char quality, signal;
u8 rate;
u32 *tmp, *tmp2;
u8 rx_desc_size;
u8 padding;
char rxpower = 0;
u32 RXAGC = 0;
long RxAGC_dBm = 0;
u8 LNA = 0, BB = 0;
u8 LNA_gain[4] = {02, 17, 29, 39};
u8 Antenna = 0;
struct ieee80211_hdr_4addr *hdr;
u16 fc, type;
u8 bHwError = 0, bCRC = 0, bICV = 0;
bool bCckRate = false;
u8 RSSI = 0;
long SignalStrengthIndex = 0;
struct ieee80211_rx_stats stats = {
.signal = 0,
.noise = -98,
.rate = 0,
.freq = IEEE80211_24GHZ_BAND,
};
stats.nic_type = NIC_8185B;
rx_desc_size = 8;
if ((*(priv->rxringtail)) & (1<<31)) {
/* we have got an RX int, but the descriptor
* we are pointing is empty */
priv->stats.rxnodata++;
priv->ieee80211->stats.rx_errors++;
tmp2 = NULL;
tmp = priv->rxringtail;
do {
if (tmp == priv->rxring)
tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
else
tmp -= rx_desc_size;
if (!(*tmp & (1<<31)))
tmp2 = tmp;
} while (tmp != priv->rxring);
if (tmp2)
priv->rxringtail = tmp2;
}
/* while there are filled descriptors */
while (!(*(priv->rxringtail) & (1<<31))) {
if (*(priv->rxringtail) & (1<<26))
DMESGW("RX buffer overflow");
if (*(priv->rxringtail) & (1<<12))
priv->stats.rxicverr++;
if (*(priv->rxringtail) & (1<<27)) {
priv->stats.rxdmafail++;
/* DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); */
goto drop;
}
pci_dma_sync_single_for_cpu(priv->pdev,
priv->rxbuffer->dma,
priv->rxbuffersize * sizeof(u8),
PCI_DMA_FROMDEVICE);
first = *(priv->rxringtail) & (1<<29) ? 1 : 0;
if (first)
priv->rx_prevlen = 0;
last = *(priv->rxringtail) & (1<<28) ? 1 : 0;
if (last) {
lastlen = ((*priv->rxringtail) & 0xfff);
/* if the last descriptor (that should
* tell us the total packet len) tell
* us something less than the descriptors
* len we had until now, then there is some
* problem..
* workaround to prevent kernel panic
*/
if (lastlen < priv->rx_prevlen)
len = 0;
else
len = lastlen-priv->rx_prevlen;
if (*(priv->rxringtail) & (1<<13)) {
if ((*(priv->rxringtail) & 0xfff) < 500)
priv->stats.rxcrcerrmin++;
else if ((*(priv->rxringtail) & 0x0fff) > 1000)
priv->stats.rxcrcerrmax++;
else
priv->stats.rxcrcerrmid++;
}
} else {
len = priv->rxbuffersize;
}
if (first && last) {
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
} else if (first) {
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
if (padding)
len -= 2;
} else {
padding = 0;
}
padding = 0;
priv->rx_prevlen += len;
if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) {
/* HW is probably passing several buggy frames
* without FD or LD flag set.
* Throw this garbage away to prevent skb
* memory exhausting
*/
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb_complete = 1;
}
signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16);
signal = (signal & 0xfe) >> 1;
quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff));
stats.mac_time[0] = *(priv->rxringtail+1);
stats.mac_time[1] = *(priv->rxringtail+2);
rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42;
RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f);
rate = ((*(priv->rxringtail)) &
((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
stats.rate = rtl8180_rate2rate(rate);
Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1;
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
RxAGC_dBm = rxpower+1; /* bias */
} else { /* CCK rate. */
RxAGC_dBm = signal; /* bit 0 discard */
LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */
BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */
RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
RxAGC_dBm += 4; /* bias */
}
if (RxAGC_dBm & 0x80) /* absolute value */
RXAGC = ~(RxAGC_dBm)+1;
bCckRate = rtl8180_IsWirelessBMode(stats.rate);
/* Translate RXAGC into 1-100. */
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
if (RXAGC > 90)
RXAGC = 90;
else if (RXAGC < 25)
RXAGC = 25;
RXAGC = (90-RXAGC)*100/65;
} else { /* CCK rate. */
if (RXAGC > 95)
RXAGC = 95;
else if (RXAGC < 30)
RXAGC = 30;
RXAGC = (95-RXAGC)*100/65;
}
priv->SignalStrength = (u8)RXAGC;
priv->RecvSignalPower = RxAGC_dBm;
priv->RxPower = rxpower;
priv->RSSI = RSSI;
/* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
if (quality >= 127)
quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */
else if (quality < 27)
quality = 100;
else
quality = 127 - quality;
priv->SignalQuality = quality;
stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */
stats.signalstrength = RXAGC;
if (stats.signalstrength > 100)
stats.signalstrength = 100;
stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
/* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) |
(((*(priv->rxringtail)) & (0x04000000)) != 0) |
(((*(priv->rxringtail)) & (0x08000000)) != 0) |
(((~(*(priv->rxringtail))) & (0x10000000)) != 0) |
(((~(*(priv->rxringtail))) & (0x20000000)) != 0);
bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf;
fc = le16_to_cpu(hdr->frame_ctl);
type = WLAN_FC_GET_TYPE(fc);
if (IEEE80211_FTYPE_CTL != type &&
!bHwError && !bCRC && !bICV &&
eqMacAddr(priv->ieee80211->current_network.bssid,
fc & IEEE80211_FCTL_TODS ? hdr->addr1 :
fc & IEEE80211_FCTL_FROMDS ? hdr->addr2 :
hdr->addr3)) {
/* Perform signal smoothing for dynamic
* mechanism on demand. This is different
* with PerformSignalSmoothing8185 in smoothing
* fomula. No dramatic adjustion is apply
* because dynamic mechanism need some degree
* of correctness. */
PerformUndecoratedSignalSmoothing8185(priv, bCckRate);
/* For good-looking singal strength. */
SignalStrengthIndex = NetgearSignalStrengthTranslate(
priv->LastSignalStrengthInPercent,
priv->SignalStrength);
priv->LastSignalStrengthInPercent = SignalStrengthIndex;
priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
/*
* We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
* so we record the correct power here.
*/
priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
/* Figure out which antenna that received the last packet. */
priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
if (first) {
if (!priv->rx_skb_complete) {
/* seems that HW sometimes fails to receive and
doesn't provide the last descriptor */
dev_kfree_skb_any(priv->rx_skb);
priv->stats.rxnolast++;
}
priv->rx_skb = dev_alloc_skb(len+2);
if (!priv->rx_skb)
goto drop;
priv->rx_skb_complete = 0;
priv->rx_skb->dev = dev;
} else {
/* if we are here we should have already RXed
* the first frame.
* If we get here and the skb is not allocated then
* we have just throw out garbage (skb not allocated)
* and we are still rxing garbage....
*/
if (!priv->rx_skb_complete) {
tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2);
if (!tmp_skb)
goto drop;
tmp_skb->dev = dev;
memcpy(skb_put(tmp_skb, priv->rx_skb->len),
priv->rx_skb->data,
priv->rx_skb->len);
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb = tmp_skb;
}
}
if (!priv->rx_skb_complete) {
if (padding) {
memcpy(skb_put(priv->rx_skb, len),
(((unsigned char *)priv->rxbuffer->buf) + 2), len);
} else {
memcpy(skb_put(priv->rx_skb, len),
priv->rxbuffer->buf, len);
}
}
if (last && !priv->rx_skb_complete) {
if (priv->rx_skb->len > 4)
skb_trim(priv->rx_skb, priv->rx_skb->len-4);
if (!ieee80211_rtl_rx(priv->ieee80211,
priv->rx_skb, &stats))
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb_complete = 1;
}
pci_dma_sync_single_for_device(priv->pdev,
priv->rxbuffer->dma,
priv->rxbuffersize * sizeof(u8),
PCI_DMA_FROMDEVICE);
drop: /* this is used when we have not enough mem */
/* restore the descriptor */
*(priv->rxringtail+2) = priv->rxbuffer->dma;
*(priv->rxringtail) = *(priv->rxringtail) & ~0xfff;
*(priv->rxringtail) =
*(priv->rxringtail) | priv->rxbuffersize;
*(priv->rxringtail) =
*(priv->rxringtail) | (1<<31);
priv->rxringtail += rx_desc_size;
if (priv->rxringtail >=
(priv->rxring)+(priv->rxringcount)*rx_desc_size)
priv->rxringtail = priv->rxring;
priv->rxbuffer = (priv->rxbuffer->next);
}
}
static void rtl8180_dma_kick(struct net_device *dev, int priority)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
write_nic_byte(dev, TX_DMA_POLLING,
(1 << (priority + 1)) | priv->dma_poll_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
force_pci_posting(dev);
}
static void rtl8180_data_hard_stop(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ;
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
static void rtl8180_data_hard_resume(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ);
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
/*
* This function TX data frames when the ieee80211 stack requires this.
* It checks also if we need to stop the ieee tx queue, eventually do it
*/
static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev,
int rate)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int mode;
struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
unsigned long flags;
int priority;
mode = priv->ieee80211->iw_mode;
rate = ieeerate2rtlrate(rate);
/*
* This function doesn't require lock because we make
* sure it's called with the tx_lock already acquired.
* this come from the kernel's hard_xmit callback (through
* the ieee stack, or from the try_wake_queue (again through
* the ieee stack.
*/
priority = AC2Q(skb->priority);
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->ieee80211->bHwRadioOff) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
return;
}
if (!check_nic_enought_desc(dev, priority)) {
DMESGW("Error: no descriptor left by previous TX (avail %d) ",
get_curr_tx_free_desc(dev, priority));
ieee80211_rtl_stop_queue(priv->ieee80211);
}
rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate);
if (!check_nic_enought_desc(dev, priority))
ieee80211_rtl_stop_queue(priv->ieee80211);
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
/*
* This is a rough attempt to TX a frame
* This is called by the ieee 80211 stack to TX management frames.
* If the ring is full packets are dropped (for data frame the queue
* is stopped before this can happen). For this reason it is better
* if the descriptors are larger than the largest management frame
* we intend to TX: i'm unsure what the HW does if it will not find
* the last fragment of a frame because it has been dropped...
* Since queues for Management and Data frames are different we
* might use a different lock than tx_lock (for example mgmt_tx_lock)
*/
/* these function may loop if invoked with 0 descriptors or 0 len buffer */
static int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
unsigned long flags;
int priority;
priority = MANAGE_PRIORITY;
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->ieee80211->bHwRadioOff) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
rtl8180_tx(dev, skb->data, skb->len, priority,
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
priv->ieee80211->stats.tx_bytes += skb->len;
priv->ieee80211->stats.tx_packets++;
spin_unlock_irqrestore(&priv->tx_lock, flags);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
/* longpre 144+48 shortpre 72+24 */
u16 rtl8180_len2duration(u32 len, short rate, short *ext)
{
u16 duration;
u16 drift;
*ext = 0;
switch (rate) {
case 0: /* 1mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x2;
drift = ((len+4)<<4) % 0x2;
if (drift == 0)
break;
duration++;
break;
case 1: /* 2mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x4;
drift = ((len+4)<<4) % 0x4;
if (drift == 0)
break;
duration++;
break;
case 2: /* 5.5mbps */
*ext = 0;
duration = ((len+4)<<4) / 0xb;
drift = ((len+4)<<4) % 0xb;
if (drift == 0)
break;
duration++;
break;
default:
case 3: /* 11mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x16;
drift = ((len+4)<<4) % 0x16;
if (drift == 0)
break;
duration++;
if (drift > 6)
break;
*ext = 1;
break;
}
return duration;
}
static void rtl8180_prepare_beacon(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct sk_buff *skb;
u16 word = read_nic_word(dev, BcnItv);
word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
write_nic_word(dev, BcnItv, word);
skb = ieee80211_get_beacon(priv->ieee80211);
if (skb) {
rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY,
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
dev_kfree_skb_any(skb);
}
}
/*
* This function do the real dirty work: it enqueues a TX command
* descriptor in the ring buffer, copyes the frame in a TX buffer
* and kicks the NIC to ensure it does the DMA transfer.
*/
short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
short morefrag, short descfrag, int rate)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *tail, *temp_tail;
u32 *begin;
u32 *buf;
int i;
int remain;
int buflen;
int count;
struct buffer *buflist;
struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
u8 dest[ETH_ALEN];
u8 bUseShortPreamble = 0;
u8 bCTSEnable = 0;
u8 bRTSEnable = 0;
u16 Duration = 0;
u16 RtsDur = 0;
u16 ThisFrameTime = 0;
u16 TxDescDuration = 0;
bool ownbit_flag = false;
switch (priority) {
case MANAGE_PRIORITY:
tail = priv->txmapringtail;
begin = priv->txmapring;
buflist = priv->txmapbufstail;
count = priv->txringcount;
break;
case BK_PRIORITY:
tail = priv->txbkpringtail;
begin = priv->txbkpring;
buflist = priv->txbkpbufstail;
count = priv->txringcount;
break;
case BE_PRIORITY:
tail = priv->txbepringtail;
begin = priv->txbepring;
buflist = priv->txbepbufstail;
count = priv->txringcount;
break;
case VI_PRIORITY:
tail = priv->txvipringtail;
begin = priv->txvipring;
buflist = priv->txvipbufstail;
count = priv->txringcount;
break;
case VO_PRIORITY:
tail = priv->txvopringtail;
begin = priv->txvopring;
buflist = priv->txvopbufstail;
count = priv->txringcount;
break;
case HI_PRIORITY:
tail = priv->txhpringtail;
begin = priv->txhpring;
buflist = priv->txhpbufstail;
count = priv->txringcount;
break;
case BEACON_PRIORITY:
tail = priv->txbeaconringtail;
begin = priv->txbeaconring;
buflist = priv->txbeaconbufstail;
count = priv->txbeaconcount;
break;
default:
return -1;
break;
}
memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
if (is_multicast_ether_addr(dest)) {
Duration = 0;
RtsDur = 0;
bRTSEnable = 0;
bCTSEnable = 0;
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
0, bUseShortPreamble);
TxDescDuration = ThisFrameTime;
} else { /* Unicast packet */
u16 AckTime;
/* YJ,add,080828,for Keep alive */
priv->NumTxUnicast++;
/* Figure out ACK rate according to BSS basic rate
* and Tx rate. */
AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
u16 RtsTime, CtsTime;
/* u16 CtsRate; */
bRTSEnable = 1;
bCTSEnable = 0;
/* Rate and time required for RTS. */
RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
/* Rate and time required for CTS. */
CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
/* Figure out time required to transmit this frame. */
ThisFrameTime = ComputeTxTime(len + sCrcLng,
rtl8180_rate2rate(rate),
0,
bUseShortPreamble);
/* RTS-CTS-ThisFrame-ACK. */
RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
TxDescDuration = RtsTime + RtsDur;
} else { /* Normal case. */
bCTSEnable = 0;
bRTSEnable = 0;
RtsDur = 0;
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
0, bUseShortPreamble);
TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
}
if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
/* ThisFrame-ACK. */
Duration = aSifsTime + AckTime;
} else { /* One or more fragments remained. */
u16 NextFragTime;
NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
rtl8180_rate2rate(rate),
0,
bUseShortPreamble);
/* ThisFrag-ACk-NextFrag-ACK. */
Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
}
} /* End of Unicast packet */
frag_hdr->duration_id = Duration;
buflen = priv->txbuffsize;
remain = len;
temp_tail = tail;
while (remain != 0) {
mb();
if (!buflist) {
DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
return -1;
}
buf = buflist->buf;
if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) {
DMESGW("No more TX desc, returning %x of %x",
remain, len);
priv->stats.txrdu++;
return remain;
}
*tail = 0; /* zeroes header */
*(tail+1) = 0;
*(tail+3) = 0;
*(tail+5) = 0;
*(tail+6) = 0;
*(tail+7) = 0;
/* FIXME: this should be triggered by HW encryption parameters.*/
*tail |= (1<<15); /* no encrypt */
if (remain == len && !descfrag) {
ownbit_flag = false;
*tail = *tail | (1<<29) ; /* fist segment of the packet */
*tail = *tail | (len);
} else {
ownbit_flag = true;
}
for (i = 0; i < buflen && remain > 0; i++, remain--) {
((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
if (remain == 4 && i+4 >= buflen)
break;
/* ensure the last desc has at least 4 bytes payload */
}
txbuf = txbuf + i;
*(tail+3) = *(tail+3) & ~0xfff;
*(tail+3) = *(tail+3) | i; /* buffer length */
/* Use short preamble or not */
if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
; /* *tail |= (1<<16); */ /* enable short preamble mode. */
if (bCTSEnable)
*tail |= (1<<18);
if (bRTSEnable) { /* rts enable */
*tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
*tail |= (1<<23); /* rts enable */
*(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
}
*(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
/* *(tail+3) |= (0xe6<<16); */
*(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
*tail = *tail | ((rate&0xf) << 24);
if (morefrag)
*tail = (*tail) | (1<<17); /* more fragment */
if (!remain)
*tail = (*tail) | (1<<28); /* last segment of frame */
*(tail+5) = *(tail+5)|(2<<27);
*(tail+7) = *(tail+7)|(1<<4);
wmb();
if (ownbit_flag)
*tail = *tail | (1<<31); /* descriptor ready to be txed */
if ((tail - begin)/8 == count-1)
tail = begin;
else
tail = tail+8;
buflist = buflist->next;
mb();
switch (priority) {
case MANAGE_PRIORITY:
priv->txmapringtail = tail;
priv->txmapbufstail = buflist;
break;
case BK_PRIORITY:
priv->txbkpringtail = tail;
priv->txbkpbufstail = buflist;
break;
case BE_PRIORITY:
priv->txbepringtail = tail;
priv->txbepbufstail = buflist;
break;
case VI_PRIORITY:
priv->txvipringtail = tail;
priv->txvipbufstail = buflist;
break;
case VO_PRIORITY:
priv->txvopringtail = tail;
priv->txvopbufstail = buflist;
break;
case HI_PRIORITY:
priv->txhpringtail = tail;
priv->txhpbufstail = buflist;
break;
case BEACON_PRIORITY:
/*
* The HW seems to be happy with the 1st
* descriptor filled and the 2nd empty...
* So always update descriptor 1 and never
* touch 2nd
*/
break;
}
}
*temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */
rtl8180_dma_kick(dev, priority);
return 0;
}
void rtl8180_irq_rx_tasklet(struct r8180_priv *priv);
static void rtl8180_link_change(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u16 beacon_interval;
struct ieee80211_network *net = &priv->ieee80211->current_network;
rtl8180_update_msr(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]);
write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]);
beacon_interval = read_nic_word(dev, BEACON_INTERVAL);
beacon_interval &= ~BEACON_INTERVAL_MASK;
beacon_interval |= net->beacon_interval;
write_nic_word(dev, BEACON_INTERVAL, beacon_interval);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
rtl8180_set_chan(dev, priv->chan);
}
static void rtl8180_rq_tx_ack(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
priv->ack_tx_to_ieee = 1;
}
static short rtl8180_is_tx_queue_empty(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *d;
for (d = priv->txmapring;
d < priv->txmapring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txbkpring;
d < priv->txbkpring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txbepring;
d < priv->txbepring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txvipring;
d < priv->txvipring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txvopring;
d < priv->txvopring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txhpring;
d < priv->txhpring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
return 1;
}
static void rtl8180_hw_wakeup(struct net_device *dev)
{
unsigned long flags;
struct r8180_priv *priv = ieee80211_priv(dev);
spin_lock_irqsave(&priv->ps_lock, flags);
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
if (priv->rf_wakeup)
priv->rf_wakeup(dev);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
static void rtl8180_hw_sleep_down(struct net_device *dev)
{
unsigned long flags;
struct r8180_priv *priv = ieee80211_priv(dev);
spin_lock_irqsave(&priv->ps_lock, flags);
if (priv->rf_sleep)
priv->rf_sleep(dev);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 rb = jiffies;
unsigned long flags;
spin_lock_irqsave(&priv->ps_lock, flags);
/*
* Writing HW register with 0 equals to disable
* the timer, that is not really what we want
*/
tl -= MSECS(4+16+7);
/*
* If the interval in witch we are requested to sleep is too
* short then give up and remain awake
*/
if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
|| ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
spin_unlock_irqrestore(&priv->ps_lock, flags);
printk("too short to sleep\n");
return;
}
{
u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
/* as tl may be less than rb */
queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
}
/*
* If we suspect the TimerInt is gone beyond tl
* while setting it, then give up
*/
if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) ||
((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
spin_unlock_irqrestore(&priv->ps_lock, flags);
return;
}
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
static void rtl8180_wmm_param_update(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
struct net_device *dev = ieee->dev;
u8 *ac_param = (u8 *)(ieee->current_network.wmm_param);
u8 mode = ieee->current_network.mode;
AC_CODING eACI;
AC_PARAM AcParam;
PAC_PARAM pAcParam;
u8 i;
if (!ieee->current_network.QoS_Enable) {
/* legacy ac_xx_param update */
AcParam.longData = 0;
AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
AcParam.f.AciAifsn.f.ACM = 0;
AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
AcParam.f.TXOPLimit = 0;
for (eACI = 0; eACI < AC_MAX; eACI++) {
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
{
u8 u1bAIFS;
u32 u4bAcParam;
pAcParam = (PAC_PARAM)(&AcParam);
/* Retrieve parameters to update. */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
switch (eACI) {
case AC1_BK:
write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
break;
case AC0_BE:
write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
break;
case AC2_VI:
write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
break;
case AC3_VO:
write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
break;
default:
pr_warn("SetHwReg8185():invalid ACI: %d!\n",
eACI);
break;
}
}
}
return;
}
for (i = 0; i < AC_MAX; i++) {
/* AcParam.longData = 0; */
pAcParam = (AC_PARAM *)ac_param;
{
AC_CODING eACI;
u8 u1bAIFS;
u32 u4bAcParam;
/* Retrieve parameters to update. */
eACI = pAcParam->f.AciAifsn.f.ACI;
/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
(((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
(((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
switch (eACI) {
case AC1_BK:
write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
break;
case AC0_BE:
write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
break;
case AC2_VI:
write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
break;
case AC3_VO:
write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
break;
default:
pr_warn("SetHwReg8185(): invalid ACI: %d !\n",
eACI);
break;
}
}
ac_param += (sizeof(AC_PARAM));
}
}
void rtl8180_restart_wq(struct work_struct *work);
/* void rtl8180_rq_tx_ack(struct work_struct *work); */
void rtl8180_watch_dog_wq(struct work_struct *work);
void rtl8180_hw_wakeup_wq(struct work_struct *work);
void rtl8180_hw_sleep_wq(struct work_struct *work);
void rtl8180_sw_antenna_wq(struct work_struct *work);
void rtl8180_watch_dog(struct net_device *dev);
static void watch_dog_adaptive(unsigned long data)
{
struct r8180_priv *priv = ieee80211_priv((struct net_device *)data);
if (!priv->up) {
DMESG("<----watch_dog_adaptive():driver is not up!\n");
return;
}
/* Tx High Power Mechanism. */
if (CheckHighPower((struct net_device *)data))
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
/* Tx Power Tracking on 87SE. */
if (CheckTxPwrTracking((struct net_device *)data))
TxPwrTracking87SE((struct net_device *)data);
/* Perform DIG immediately. */
if (CheckDig((struct net_device *)data))
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
rtl8180_watch_dog((struct net_device *)data);
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
add_timer(&priv->watch_dog_timer);
}
static CHANNEL_LIST ChannelPlan[] = {
{{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */
{{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */
{{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. */
{{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. */
{{14,36,40,44,48,52,56,60,64},9}, /* MKK */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */
{{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 */
{{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 */
};
static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
{
int i;
/* lzm add 080826 */
ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1;
ieee->IbssStartChnl = 0;
switch (channel_plan) {
case COUNTRY_CODE_FCC:
case COUNTRY_CODE_IC:
case COUNTRY_CODE_ETSI:
case COUNTRY_CODE_SPAIN:
case COUNTRY_CODE_FRANCE:
case COUNTRY_CODE_MKK:
case COUNTRY_CODE_MKK1:
case COUNTRY_CODE_ISRAEL:
case COUNTRY_CODE_TELEC:
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
if (ChannelPlan[channel_plan].Len != 0) {
/* Clear old channel map */
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
/* Set new channel map */
for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
if (ChannelPlan[channel_plan].Channel[i] <= 14)
GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
}
}
break;
}
case COUNTRY_CODE_GLOBAL_DOMAIN:
{
GET_DOT11D_INFO(ieee)->bEnabled = false;
Dot11d_Reset(ieee);
ieee->bGlobalDomain = true;
break;
}
case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
{
ieee->MinPassiveChnlNum = 12;
ieee->IbssStartChnl = 10;
break;
}
default:
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
for (i = 1; i <= 14; i++)
GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
break;
}
}
}
void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
/* YJ,add,080828 */
static void rtl8180_statistics_init(struct Stats *pstats)
{
memset(pstats, 0, sizeof(struct Stats));
}
static void rtl8180_link_detect_init(plink_detect_t plink_detect)
{
memset(plink_detect, 0, sizeof(link_detect_t));
plink_detect->SlotNum = DEFAULT_SLOT_NUM;
}
/* YJ,add,080828,end */
static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
{
struct net_device *dev = eeprom->data;
u8 reg = read_nic_byte(dev, EPROM_CMD);
eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
}
static void rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom)
{
struct net_device *dev = eeprom->data;
u8 reg = 2 << 6;
if (eeprom->reg_data_in)
reg |= RTL818X_EEPROM_CMD_WRITE;
if (eeprom->reg_data_out)
reg |= RTL818X_EEPROM_CMD_READ;
if (eeprom->reg_data_clock)
reg |= RTL818X_EEPROM_CMD_CK;
if (eeprom->reg_chip_select)
reg |= RTL818X_EEPROM_CMD_CS;
write_nic_byte(dev, EPROM_CMD, reg);
read_nic_byte(dev, EPROM_CMD);
udelay(10);
}
short rtl8180_init(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u16 word;
u16 usValue;
u16 tmpu16;
int i, j;
struct eeprom_93cx6 eeprom;
u16 eeprom_val;
eeprom.data = dev;
eeprom.register_read = rtl8187se_eeprom_register_read;
eeprom.register_write = rtl8187se_eeprom_register_write;
eeprom.width = PCI_EEPROM_WIDTH_93C46;
eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
priv->channel_plan = eeprom_val & 0xFF;
if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) {
printk("rtl8180_init:Error channel plan! Set to default.\n");
priv->channel_plan = 0;
}
DMESG("Channel plan is %d\n", priv->channel_plan);
rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211);
/* FIXME: these constants are placed in a bad pleace. */
priv->txbuffsize = 2048; /* 1024; */
priv->txringcount = 32; /* 32; */
priv->rxbuffersize = 2048; /* 1024; */
priv->rxringcount = 64; /* 32; */
priv->txbeaconcount = 2;
priv->rx_skb_complete = 1;
priv->RFChangeInProgress = false;
priv->SetRFPowerStateInProgress = false;
priv->RFProgType = 0;
priv->irq_enabled = 0;
rtl8180_statistics_init(&priv->stats);
rtl8180_link_detect_init(&priv->link_detect);
priv->ack_tx_to_ieee = 0;
priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
priv->ieee80211->iw_mode = IW_MODE_INFRA;
priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN |
IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;
priv->ieee80211->active_scan = 1;
priv->ieee80211->rate = 110; /* 11 mbps */
priv->ieee80211->modulation = IEEE80211_CCK_MODULATION;
priv->ieee80211->host_encrypt = 1;
priv->ieee80211->host_decrypt = 1;
priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup;
priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack;
priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep;
priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty;
priv->hw_wep = hwwep;
priv->dev = dev;
priv->retry_rts = DEFAULT_RETRY_RTS;
priv->retry_data = DEFAULT_RETRY_DATA;
priv->RFChangeInProgress = false;
priv->SetRFPowerStateInProgress = false;
priv->RFProgType = 0;
priv->bInactivePs = true; /* false; */
priv->ieee80211->bInactivePs = priv->bInactivePs;
priv->bSwRfProcessing = false;
priv->eRFPowerState = eRfOff;
priv->RfOffReason = 0;
priv->LedStrategy = SW_LED_MODE0;
priv->TxPollingTimes = 0; /* lzm add 080826 */
priv->bLeisurePs = true;
priv->dot11PowerSaveMode = eActive;
priv->AdMinCheckPeriod = 5;
priv->AdMaxCheckPeriod = 10;
priv->AdMaxRxSsThreshold = 30; /* 60->30 */
priv->AdRxSsThreshold = 20; /* 50->20 */
priv->AdCheckPeriod = priv->AdMinCheckPeriod;
priv->AdTickCount = 0;
priv->AdRxSignalStrength = -1;
priv->RegSwAntennaDiversityMechanism = 0;
priv->RegDefaultAntenna = 0;
priv->SignalStrength = 0;
priv->AdRxOkCnt = 0;
priv->CurrAntennaIndex = 0;
priv->AdRxSsBeforeSwitched = 0;
init_timer(&priv->SwAntennaDiversityTimer);
priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
priv->bDigMechanism = true;
priv->InitialGain = 6;
priv->bXtalCalibration = false;
priv->XtalCal_Xin = 0;
priv->XtalCal_Xout = 0;
priv->bTxPowerTrack = false;
priv->ThermalMeter = 0;
priv->FalseAlarmRegValue = 0;
priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
priv->DIG_NumberFallbackVote = 0;
priv->DIG_NumberUpgradeVote = 0;
priv->LastSignalStrengthInPercent = 0;
priv->Stats_SignalStrength = 0;
priv->LastRxPktAntenna = 0;
priv->SignalQuality = 0; /* in 0-100 index. */
priv->Stats_SignalQuality = 0;
priv->RecvSignalPower = 0; /* in dBm. */
priv->Stats_RecvSignalPower = 0;
priv->AdMainAntennaRxOkCnt = 0;
priv->AdAuxAntennaRxOkCnt = 0;
priv->bHWAdSwitched = false;
priv->bRegHighPowerMechanism = true;
priv->RegHiPwrUpperTh = 77;
priv->RegHiPwrLowerTh = 75;
priv->RegRSSIHiPwrUpperTh = 70;
priv->RegRSSIHiPwrLowerTh = 20;
priv->bCurCCKPkt = false;
priv->UndecoratedSmoothedSS = -1;
priv->bToUpdateTxPwr = false;
priv->CurCCKRSSI = 0;
priv->RxPower = 0;
priv->RSSI = 0;
priv->NumTxOkTotal = 0;
priv->NumTxUnicast = 0;
priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
priv->CurrRetryCnt = 0;
priv->LastRetryCnt = 0;
priv->LastTxokCnt = 0;
priv->LastRxokCnt = 0;
priv->LastRetryRate = 0;
priv->bTryuping = 0;
priv->CurrTxRate = 0;
priv->CurrRetryRate = 0;
priv->TryupingCount = 0;
priv->TryupingCountNoData = 0;
priv->TryDownCountLowData = 0;
priv->LastTxOKBytes = 0;
priv->LastFailTxRate = 0;
priv->LastFailTxRateSS = 0;
priv->FailTxRateCount = 0;
priv->LastTxThroughput = 0;
priv->NumTxOkBytesTotal = 0;
priv->ForcedDataRate = 0;
priv->RegBModeGainStage = 1;
priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
spin_lock_init(&priv->irq_th_lock);
spin_lock_init(&priv->tx_lock);
spin_lock_init(&priv->ps_lock);
spin_lock_init(&priv->rf_ps_lock);
sema_init(&priv->wx_sem, 1);
INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq);
INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,
(void *)rtl8180_hw_wakeup_wq);
INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,
(void *)rtl8180_hw_sleep_wq);
INIT_WORK(&priv->ieee80211->wmm_param_update_wq,
(void *)rtl8180_wmm_param_update);
INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,
(void *)rtl8180_rate_adapter);
INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,
(void *)rtl8180_hw_dig_wq);
INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,
(void *)rtl8180_tx_pw_wq);
INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,
(void *) GPIOChangeRFWorkItemCallBack);
tasklet_init(&priv->irq_rx_tasklet,
(void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
(unsigned long)priv);
init_timer(&priv->watch_dog_timer);
priv->watch_dog_timer.data = (unsigned long)dev;
priv->watch_dog_timer.function = watch_dog_adaptive;
init_timer(&priv->rateadapter_timer);
priv->rateadapter_timer.data = (unsigned long)dev;
priv->rateadapter_timer.function = timer_rate_adaptive;
priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
priv->bEnhanceTxPwr = false;
priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit;
priv->ieee80211->set_chan = rtl8180_set_chan;
priv->ieee80211->link_change = rtl8180_link_change;
priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit;
priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop;
priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume;
priv->ieee80211->init_wmmparam_flag = 0;
priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon;
priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable;
priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
priv->ShortRetryLimit = 7;
priv->LongRetryLimit = 7;
priv->EarlyRxThreshold = 7;
priv->TransmitConfig = (1<<TCR_DurProcMode_OFFSET) |
(7<<TCR_MXDMA_OFFSET) |
(priv->ShortRetryLimit<<TCR_SRL_OFFSET) |
(priv->LongRetryLimit<<TCR_LRL_OFFSET);
priv->ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF |
RCR_AB | RCR_AM | RCR_APM |
(7<<RCR_MXDMA_OFFSET) |
(priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) |
(priv->EarlyRxThreshold == 7 ?
RCR_ONLYERLPKT : 0);
priv->IntrMask = IMR_TMGDOK | IMR_TBDER |
IMR_THPDER | IMR_THPDOK |
IMR_TVODER | IMR_TVODOK |
IMR_TVIDER | IMR_TVIDOK |
IMR_TBEDER | IMR_TBEDOK |
IMR_TBKDER | IMR_TBKDOK |
IMR_RDU |
IMR_RER | IMR_ROK |
IMR_RQoSOK;
priv->InitialGain = 6;
DMESG("MAC controller is a RTL8187SE b/g");