Staging: add agnx wireless driver

This driver is for the Airgo AGNX00 wireless chip.

From: Li YanBo <dreamfly281@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Li YanBo 2008-10-27 20:32:57 -07:00 committed by Greg Kroah-Hartman
parent 470c5736ff
commit 0f22aab897
17 changed files with 5211 additions and 0 deletions

View File

@ -63,5 +63,7 @@ source "drivers/staging/at76_usb/Kconfig"
source "drivers/staging/poch/Kconfig"
source "drivers/staging/agnx/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View File

@ -14,3 +14,4 @@ obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_USB_ATMEL) += at76_usb/
obj-$(CONFIG_POCH) += poch/
obj-$(CONFIG_AGNX) += agnx/

View File

@ -0,0 +1,5 @@
config AGNX
tristate "Wireless Airgo AGNX support"
depends on WLAN_80211 && MAC80211
---help---
This is an experimental driver for Airgo AGNX00 wireless chip.

View File

@ -0,0 +1,8 @@
obj-$(CONFIG_AGNX) += agnx.o
agnx-objs := rf.o \
pci.o \
xmit.o \
table.o \
sta.o \
phy.o

22
drivers/staging/agnx/TODO Normal file
View File

@ -0,0 +1,22 @@
2008 7/18
The RX has can't receive OFDM packet correctly,
Guess it need be do RX calibrate.
before 2008 3/1
1: The RX get too much "CRC failed" pakets, it make the card work very unstable,
2: After running a while, the card will get infinity "RX Frame" and "Error"
interrupt, not know the root reason so far, try to fix it
3: Using two tx queue txd and txm but not only txm.
4: Set the hdr correctly.
5: Try to do recalibrate correvtly
6: To support G mode in future
7: Fix the mac address can't be readed and set correctly in BE machine.
8: Fix include and exclude FCS in promisous mode and manage mode
9: Using sta_notify to notice sta change
10: Turn on frame reception at the end of start
11: Guess the card support HW_MULTICAST_FILTER
12: The tx process should be implment atomic?
13: Using mac80211 function to control the TX&RX LED.

156
drivers/staging/agnx/agnx.h Normal file
View File

@ -0,0 +1,156 @@
#ifndef AGNX_H_
#define AGNX_H_
#include "xmit.h"
#define PFX KBUILD_MODNAME ": "
static inline u32 agnx_read32(void __iomem *mem_region, u32 offset)
{
return ioread32(mem_region + offset);
}
static inline void agnx_write32(void __iomem *mem_region, u32 offset, u32 val)
{
iowrite32(val, mem_region + offset);
}
/* static const struct ieee80211_rate agnx_rates_80211b[] = { */
/* { .rate = 10, */
/* .val = 0xa, */
/* .flags = IEEE80211_RATE_CCK }, */
/* { .rate = 20, */
/* .val = 0x14, */
/* .hw_value = -0x14, */
/* .flags = IEEE80211_RATE_CCK_2 }, */
/* { .rate = 55, */
/* .val = 0x37, */
/* .val2 = -0x37, */
/* .flags = IEEE80211_RATE_CCK_2 }, */
/* { .rate = 110, */
/* .val = 0x6e, */
/* .val2 = -0x6e, */
/* .flags = IEEE80211_RATE_CCK_2 } */
/* }; */
static const struct ieee80211_rate agnx_rates_80211g[] = {
/* { .bitrate = 10, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
/* { .bitrate = 20, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
/* { .bitrate = 55, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
/* { .bitrate = 110, .hw_value = 4, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
{ .bitrate = 10, .hw_value = 1, },
{ .bitrate = 20, .hw_value = 2, },
{ .bitrate = 55, .hw_value = 3, },
{ .bitrate = 110, .hw_value = 4,},
{ .bitrate = 60, .hw_value = 0xB, },
{ .bitrate = 90, .hw_value = 0xF, },
{ .bitrate = 120, .hw_value = 0xA },
{ .bitrate = 180, .hw_value = 0xE, },
// { .bitrate = 240, .hw_value = 0xd, },
{ .bitrate = 360, .hw_value = 0xD, },
{ .bitrate = 480, .hw_value = 0x8, },
{ .bitrate = 540, .hw_value = 0xC, },
};
static const struct ieee80211_channel agnx_channels[] = {
{ .center_freq = 2412, .hw_value = 1, },
{ .center_freq = 2417, .hw_value = 2, },
{ .center_freq = 2422, .hw_value = 3, },
{ .center_freq = 2427, .hw_value = 4, },
{ .center_freq = 2432, .hw_value = 5, },
{ .center_freq = 2437, .hw_value = 6, },
{ .center_freq = 2442, .hw_value = 7, },
{ .center_freq = 2447, .hw_value = 8, },
{ .center_freq = 2452, .hw_value = 9, },
{ .center_freq = 2457, .hw_value = 10, },
{ .center_freq = 2462, .hw_value = 11, },
{ .center_freq = 2467, .hw_value = 12, },
{ .center_freq = 2472, .hw_value = 13, },
{ .center_freq = 2484, .hw_value = 14, },
};
#define NUM_DRIVE_MODES 2
/* Agnx operate mode */
enum {
AGNX_MODE_80211A,
AGNX_MODE_80211A_OOB,
AGNX_MODE_80211A_MIMO,
AGNX_MODE_80211B_SHORT,
AGNX_MODE_80211B_LONG,
AGNX_MODE_80211G,
AGNX_MODE_80211G_OOB,
AGNX_MODE_80211G_MIMO,
};
enum {
AGNX_UNINIT,
AGNX_START,
AGNX_STOP,
};
struct agnx_priv {
struct pci_dev *pdev;
struct ieee80211_hw *hw;
spinlock_t lock;
struct mutex mutex;
unsigned int init_status;
void __iomem *ctl; /* pointer to base ram address */
void __iomem *data; /* pointer to mem region #2 */
struct agnx_ring rx;
struct agnx_ring txm;
struct agnx_ring txd;
/* Need volatile? */
u32 irq_status;
struct delayed_work periodic_work; /* Periodic tasks like recalibrate*/
struct ieee80211_low_level_stats stats;
// unsigned int phymode;
int mode;
int channel;
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
u8 mac_addr[ETH_ALEN];
u8 revid;
struct ieee80211_supported_band band;
};
#define AGNX_CHAINS_MAX 6
#define AGNX_PERIODIC_DELAY 60000 /* unit: ms */
#define LOCAL_STAID 0 /* the station entry for the card itself */
#define BSSID_STAID 1 /* the station entry for the bsssid AP */
#define spi_delay() udelay(40)
#define eeprom_delay() udelay(40)
#define routing_table_delay() udelay(50)
/* PDU pool MEM region #2 */
#define AGNX_PDUPOOL 0x40000 /* PDU pool */
#define AGNX_PDUPOOL_SIZE 0x8000 /* PDU pool size*/
#define AGNX_PDU_TX_WQ 0x41000 /* PDU list TX workqueue */
#define AGNX_PDU_FREE 0x41800 /* Free Pool */
#define PDU_SIZE 0x80 /* Free Pool node size */
#define PDU_FREE_CNT 0xd0 /* Free pool node count */
/* RF stuffs */
extern void rf_chips_init(struct agnx_priv *priv);
extern void spi_rc_write(void __iomem *mem_region, u32 chip_ids, u32 sw);
extern void calibrate_oscillator(struct agnx_priv *priv);
extern void do_calibration(struct agnx_priv *priv);
extern void antenna_calibrate(struct agnx_priv *priv);
extern void __antenna_calibrate(struct agnx_priv *priv);
extern void print_offsets(struct agnx_priv *priv);
extern int agnx_set_channel(struct agnx_priv *priv, unsigned int channel);
#endif /* AGNX_H_ */

View File

@ -0,0 +1,418 @@
#ifndef AGNX_DEBUG_H_
#define AGNX_DEBUG_H_
#include "agnx.h"
#include "phy.h"
#include "sta.h"
#include "xmit.h"
#define AGNX_TRACE printk(KERN_ERR PFX "function:%s line:%d\n", __func__, __LINE__)
#define PRINTK_LE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", le16_to_cpu(var))
#define PRINTK_LE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", le32_to_cpu(var))
#define PRINTK_U8(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.2x\n", var)
#define PRINTK_BE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", be16_to_cpu(var))
#define PRINTK_BE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", be32_to_cpu(var))
#define PRINTK_BITS(prefix, field) printk(KERN_DEBUG PFX #prefix ": " #field ": 0x%x\n", (reg & field) >> field##_SHIFT)
static inline void agnx_bug(char *reason)
{
printk(KERN_ERR PFX "%s\n", reason);
BUG();
}
static inline void agnx_print_desc(struct agnx_desc *desc)
{
u32 reg = be32_to_cpu(desc->frag);
PRINTK_BITS(DESC, PACKET_LEN);
if (reg & FIRST_FRAG) {
PRINTK_BITS(DESC, FIRST_PACKET_MASK);
PRINTK_BITS(DESC, FIRST_RESERV2);
PRINTK_BITS(DESC, FIRST_TKIP_ERROR);
PRINTK_BITS(DESC, FIRST_TKIP_PACKET);
PRINTK_BITS(DESC, FIRST_RESERV1);
PRINTK_BITS(DESC, FIRST_FRAG_LEN);
} else {
PRINTK_BITS(DESC, SUB_RESERV2);
PRINTK_BITS(DESC, SUB_TKIP_ERROR);
PRINTK_BITS(DESC, SUB_TKIP_PACKET);
PRINTK_BITS(DESC, SUB_RESERV1);
PRINTK_BITS(DESC, SUB_FRAG_LEN);
}
PRINTK_BITS(DESC, FIRST_FRAG);
PRINTK_BITS(DESC, LAST_FRAG);
PRINTK_BITS(DESC, OWNER);
}
static inline void dump_ieee80211b_phy_hdr(__be32 _11b0, __be32 _11b1)
{
}
static inline void agnx_print_hdr(struct agnx_hdr *hdr)
{
u32 reg;
int i;
reg = be32_to_cpu(hdr->reg0);
PRINTK_BITS(HDR, RTS);
PRINTK_BITS(HDR, MULTICAST);
PRINTK_BITS(HDR, ACK);
PRINTK_BITS(HDR, TM);
PRINTK_BITS(HDR, RELAY);
PRINTK_BITS(HDR, REVISED_FCS);
PRINTK_BITS(HDR, NEXT_BUFFER_ADDR);
reg = be32_to_cpu(hdr->reg1);
PRINTK_BITS(HDR, MAC_HDR_LEN);
PRINTK_BITS(HDR, DURATION_OVERIDE);
PRINTK_BITS(HDR, PHY_HDR_OVERIDE);
PRINTK_BITS(HDR, CRC_FAIL);
PRINTK_BITS(HDR, SEQUENCE_NUMBER);
PRINTK_BITS(HDR, BUFF_HEAD_ADDR);
reg = be32_to_cpu(hdr->reg2);
PRINTK_BITS(HDR, PDU_COUNT);
PRINTK_BITS(HDR, WEP_KEY);
PRINTK_BITS(HDR, USES_WEP_KEY);
PRINTK_BITS(HDR, KEEP_ALIVE);
PRINTK_BITS(HDR, BUFF_TAIL_ADDR);
reg = be32_to_cpu(hdr->reg3);
PRINTK_BITS(HDR, CTS_11G);
PRINTK_BITS(HDR, RTS_11G);
PRINTK_BITS(HDR, FRAG_SIZE);
PRINTK_BITS(HDR, PAYLOAD_LEN);
PRINTK_BITS(HDR, FRAG_NUM);
reg = be32_to_cpu(hdr->reg4);
PRINTK_BITS(HDR, RELAY_STAID);
PRINTK_BITS(HDR, STATION_ID);
PRINTK_BITS(HDR, WORKQUEUE_ID);
reg = be32_to_cpu(hdr->reg5);
/* printf the route flag */
PRINTK_BITS(HDR, ROUTE_HOST);
PRINTK_BITS(HDR, ROUTE_CARD_CPU);
PRINTK_BITS(HDR, ROUTE_ENCRYPTION);
PRINTK_BITS(HDR, ROUTE_TX);
PRINTK_BITS(HDR, ROUTE_RX1);
PRINTK_BITS(HDR, ROUTE_RX2);
PRINTK_BITS(HDR, ROUTE_COMPRESSION);
PRINTK_BE32(HDR, hdr->_11g0);
PRINTK_BE32(HDR, hdr->_11g1);
PRINTK_BE32(HDR, hdr->_11b0);
PRINTK_BE32(HDR, hdr->_11b1);
dump_ieee80211b_phy_hdr(hdr->_11b0, hdr->_11b1);
/* Fixme */
for (i = 0; i < ARRAY_SIZE(hdr->mac_hdr); i++) {
if (i == 0)
printk(KERN_DEBUG PFX "IEEE80211 HDR: ");
printk("%.2x ", hdr->mac_hdr[i]);
if (i + 1 == ARRAY_SIZE(hdr->mac_hdr))
printk("\n");
}
PRINTK_BE16(HDR, hdr->rts_duration);
PRINTK_BE16(HDR, hdr->last_duration);
PRINTK_BE16(HDR, hdr->sec_last_duration);
PRINTK_BE16(HDR, hdr->other_duration);
PRINTK_BE16(HDR, hdr->tx_other_duration);
PRINTK_BE16(HDR, hdr->last_11g_len);
PRINTK_BE16(HDR, hdr->other_11g_len);
PRINTK_BE16(HDR, hdr->last_11b_len);
PRINTK_BE16(HDR, hdr->other_11b_len);
/* FIXME */
reg = be16_to_cpu(hdr->reg6);
PRINTK_BITS(HDR, MBF);
PRINTK_BITS(HDR, RSVD4);
PRINTK_BE16(HDR, hdr->rx_frag_stat);
PRINTK_BE32(HDR, hdr->time_stamp);
PRINTK_BE32(HDR, hdr->phy_stats_hi);
PRINTK_BE32(HDR, hdr->phy_stats_lo);
PRINTK_BE32(HDR, hdr->mic_key0);
PRINTK_BE32(HDR, hdr->mic_key1);
} /* agnx_print_hdr */
static inline void agnx_print_rx_hdr(struct agnx_hdr *hdr)
{
agnx_print_hdr(hdr);
PRINTK_BE16(HDR, hdr->rx.rx_packet_duration);
PRINTK_BE16(HDR, hdr->rx.replay_cnt);
PRINTK_U8(HDR, hdr->rx_channel);
}
static inline void agnx_print_tx_hdr(struct agnx_hdr *hdr)
{
agnx_print_hdr(hdr);
PRINTK_U8(HDR, hdr->tx.long_retry_limit);
PRINTK_U8(HDR, hdr->tx.short_retry_limit);
PRINTK_U8(HDR, hdr->tx.long_retry_cnt);
PRINTK_U8(HDR, hdr->tx.short_retry_cnt);
PRINTK_U8(HDR, hdr->rx_channel);
}
static inline void
agnx_print_sta_power(struct agnx_priv *priv, unsigned int sta_idx)
{
struct agnx_sta_power power;
u32 reg;
get_sta_power(priv, &power, sta_idx);
reg = le32_to_cpu(power.reg);
PRINTK_BITS(STA_POWER, SIGNAL);
PRINTK_BITS(STA_POWER, RATE);
PRINTK_BITS(STA_POWER, TIFS);
PRINTK_BITS(STA_POWER, EDCF);
PRINTK_BITS(STA_POWER, CHANNEL_BOND);
PRINTK_BITS(STA_POWER, PHY_MODE);
PRINTK_BITS(STA_POWER, POWER_LEVEL);
PRINTK_BITS(STA_POWER, NUM_TRANSMITTERS);
}
static inline void
agnx_print_sta_tx_wq(struct agnx_priv *priv, unsigned int sta_idx, unsigned int wq_idx)
{
struct agnx_sta_tx_wq tx_wq;
u32 reg;
get_sta_tx_wq(priv, &tx_wq, sta_idx, wq_idx);
reg = le32_to_cpu(tx_wq.reg0);
PRINTK_BITS(STA_TX_WQ, TAIL_POINTER);
PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_LOW);
reg = le32_to_cpu(tx_wq.reg3);
PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_HIGH);
PRINTK_BITS(STA_TX_WQ, ACK_POINTER_LOW);
reg = le32_to_cpu(tx_wq.reg1);
PRINTK_BITS(STA_TX_WQ, ACK_POINTER_HIGH);
PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_TAIL_PACK_CNT);
PRINTK_BITS(STA_TX_WQ, ACK_TIMOUT_TAIL_PACK_CNT);
reg = le32_to_cpu(tx_wq.reg2);
PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_BYTE_CNT);
PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_FRAG_CNT);
PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_ACK_TYPE);
PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_VALID);
}
static inline void agnx_print_sta_traffic(struct agnx_sta_traffic *traffic)
{
u32 reg;
reg = le32_to_cpu(traffic->reg0);
PRINTK_BITS(STA_TRAFFIC, ACK_TIMOUT_CNT);
PRINTK_BITS(STA_TRAFFIC, TRAFFIC_ACK_TYPE);
PRINTK_BITS(STA_TRAFFIC, NEW_PACKET);
PRINTK_BITS(STA_TRAFFIC, TRAFFIC_VALID);
PRINTK_BITS(STA_TRAFFIC, RX_HDR_DESC_POINTER);
reg = le32_to_cpu(traffic->reg1);
PRINTK_BITS(STA_TRAFFIC, RX_PACKET_TIMESTAMP);
PRINTK_BITS(STA_TRAFFIC, TRAFFIC_RESERVED);
PRINTK_BITS(STA_TRAFFIC, SV);
PRINTK_BITS(STA_TRAFFIC, RX_SEQUENCE_NUM);
PRINTK_LE32(STA_TRAFFIC, traffic->tx_replay_cnt_low);
PRINTK_LE16(STA_TRAFFIC, traffic->tx_replay_cnt_high);
PRINTK_LE16(STA_TRAFFIC, traffic->rx_replay_cnt_high);
PRINTK_LE32(STA_TRAFFIC, traffic->rx_replay_cnt_low);
}
static inline void agnx_print_sta(struct agnx_priv *priv, unsigned int sta_idx)
{
struct agnx_sta station;
struct agnx_sta *sta = &station;
u32 reg;
unsigned int i;
get_sta(priv, sta, sta_idx);
for (i = 0; i < 4; i++)
PRINTK_LE32(STA, sta->tx_session_keys[i]);
for (i = 0; i < 4; i++)
PRINTK_LE32(STA, sta->rx_session_keys[i]);
reg = le32_to_cpu(sta->reg);
PRINTK_BITS(STA, ID_1);
PRINTK_BITS(STA, ID_0);
PRINTK_BITS(STA, ENABLE_CONCATENATION);
PRINTK_BITS(STA, ENABLE_DECOMPRESSION);
PRINTK_BITS(STA, STA_RESERVED);
PRINTK_BITS(STA, EAP);
PRINTK_BITS(STA, ED_NULL);
PRINTK_BITS(STA, ENCRYPTION_POLICY);
PRINTK_BITS(STA, DEFINED_KEY_ID);
PRINTK_BITS(STA, FIXED_KEY);
PRINTK_BITS(STA, KEY_VALID);
PRINTK_BITS(STA, STATION_VALID);
PRINTK_LE32(STA, sta->tx_aes_blks_unicast);
PRINTK_LE32(STA, sta->rx_aes_blks_unicast);
PRINTK_LE16(STA, sta->aes_format_err_unicast_cnt);
PRINTK_LE16(STA, sta->aes_replay_unicast);
PRINTK_LE16(STA, sta->aes_decrypt_err_unicast);
PRINTK_LE16(STA, sta->aes_decrypt_err_default);
PRINTK_LE16(STA, sta->single_retry_packets);
PRINTK_LE16(STA, sta->failed_tx_packets);
PRINTK_LE16(STA, sta->muti_retry_packets);
PRINTK_LE16(STA, sta->ack_timeouts);
PRINTK_LE16(STA, sta->frag_tx_cnt);
PRINTK_LE16(STA, sta->rts_brq_sent);
PRINTK_LE16(STA, sta->tx_packets);
PRINTK_LE16(STA, sta->cts_back_timeout);
PRINTK_LE32(STA, sta->phy_stats_high);
PRINTK_LE32(STA, sta->phy_stats_low);
// for (i = 0; i < 8; i++)
agnx_print_sta_traffic(sta->traffic + 0);
PRINTK_LE16(STA, sta->traffic_class0_frag_success);
PRINTK_LE16(STA, sta->traffic_class1_frag_success);
PRINTK_LE16(STA, sta->traffic_class2_frag_success);
PRINTK_LE16(STA, sta->traffic_class3_frag_success);
PRINTK_LE16(STA, sta->traffic_class4_frag_success);
PRINTK_LE16(STA, sta->traffic_class5_frag_success);
PRINTK_LE16(STA, sta->traffic_class6_frag_success);
PRINTK_LE16(STA, sta->traffic_class7_frag_success);
PRINTK_LE16(STA, sta->num_frag_non_prime_rates);
PRINTK_LE16(STA, sta->ack_timeout_non_prime_rates);
}
static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
{
u16 fctl;
int hdrlen;
DECLARE_MAC_BUF(mac);
fctl = le16_to_cpu(hdr->frame_control);
switch (fctl & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_DATA:
printk(PFX "%s DATA ", tag);
break;
case IEEE80211_FTYPE_CTL:
printk(PFX "%s CTL ", tag);
break;
case IEEE80211_FTYPE_MGMT:
printk(PFX "%s MGMT ", tag);
switch(fctl & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_ASSOC_REQ:
printk("SubType: ASSOC_REQ ");
break;
case IEEE80211_STYPE_ASSOC_RESP:
printk("SubType: ASSOC_RESP ");
break;
case IEEE80211_STYPE_REASSOC_REQ:
printk("SubType: REASSOC_REQ ");
break;
case IEEE80211_STYPE_REASSOC_RESP:
printk("SubType: REASSOC_RESP ");
break;
case IEEE80211_STYPE_PROBE_REQ:
printk("SubType: PROBE_REQ ");
break;
case IEEE80211_STYPE_PROBE_RESP:
printk("SubType: PROBE_RESP ");
break;
case IEEE80211_STYPE_BEACON:
printk("SubType: BEACON ");
break;
case IEEE80211_STYPE_ATIM:
printk("SubType: ATIM ");
break;
case IEEE80211_STYPE_DISASSOC:
printk("SubType: DISASSOC ");
break;
case IEEE80211_STYPE_AUTH:
printk("SubType: AUTH ");
break;
case IEEE80211_STYPE_DEAUTH:
printk("SubType: DEAUTH ");
break;
case IEEE80211_STYPE_ACTION:
printk("SubType: ACTION ");
break;
default:
printk("SubType: Unknow\n");
}
break;
default:
printk(PFX "%s Packet type: Unknow\n", tag);
}
hdrlen = ieee80211_hdrlen(fctl);
if (hdrlen >= 4)
printk("FC=0x%04x DUR=0x%04x",
fctl, le16_to_cpu(hdr->duration_id));
if (hdrlen >= 10)
printk(" A1=%s", print_mac(mac, hdr->addr1));
if (hdrlen >= 16)
printk(" A2=%s", print_mac(mac, hdr->addr2));
if (hdrlen >= 24)
printk(" A3=%s", print_mac(mac, hdr->addr3));
if (hdrlen >= 30)
printk(" A4=%s", print_mac(mac, hdr->addr4));
printk("\n");
}
static inline void dump_txm_registers(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i <=0x1e8; i += 4) {
printk(KERN_DEBUG PFX "TXM: %x---> 0x%.8x\n", i, ioread32(ctl + i));
}
}
static inline void dump_rxm_registers(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i <=0x108; i += 4)
printk(KERN_DEBUG PFX "RXM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2000 + i));
}
static inline void dump_bm_registers(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i <=0x90; i += 4)
printk(KERN_DEBUG PFX "BM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2c00 + i));
}
static inline void dump_cir_registers(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i <=0xb8; i += 4)
printk(KERN_DEBUG PFX "CIR: %x---> 0x%.8x\n", i, ioread32(ctl + 0x3000 + i));
}
#endif /* AGNX_DEBUG_H_ */

650
drivers/staging/agnx/pci.c Normal file
View File

@ -0,0 +1,650 @@
/**
* Airgo MIMO wireless driver
*
* Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
* Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
* works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "xmit.h"
#include "phy.h"
MODULE_AUTHOR("Li YanBo <dreamfly281@gmail.com>");
MODULE_DESCRIPTION("Airgo MIMO PCI wireless driver");
MODULE_LICENSE("GPL");
static struct pci_device_id agnx_pci_id_tbl[] __devinitdata = {
{ PCI_DEVICE(0x17cb, 0x0001) }, /* Beklin F5d8010, Netgear WGM511 etc */
{ PCI_DEVICE(0x17cb, 0x0002) }, /* Netgear Wpnt511 */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, agnx_pci_id_tbl);
static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason)
{
void __iomem *ctl = priv->ctl;
u32 reg;
if ( *reason & AGNX_STAT_RX ) {
/* Mark complete RX */
reg = ioread32(ctl + AGNX_CIR_RXCTL);
reg |= 0x4;
iowrite32(reg, ctl + AGNX_CIR_RXCTL);
/* disable Rx interrupt */
}
if ( *reason & AGNX_STAT_TX ) {
reg = ioread32(ctl + AGNX_CIR_TXDCTL);
if (reg & 0x4) {
iowrite32(reg, ctl + AGNX_CIR_TXDCTL);
*reason |= AGNX_STAT_TXD;
}
reg = ioread32(ctl + AGNX_CIR_TXMCTL);
if (reg & 0x4) {
iowrite32(reg, ctl + AGNX_CIR_TXMCTL);
*reason |= AGNX_STAT_TXM;
}
}
if ( *reason & AGNX_STAT_X ) {
/* reg = ioread32(ctl + AGNX_INT_STAT); */
/* iowrite32(reg, ctl + AGNX_INT_STAT); */
/* /\* FIXME reinit interrupt mask *\/ */
/* reg = 0xc390bf9 & ~IRQ_TX_BEACON; */
/* reg &= ~IRQ_TX_DISABLE; */
/* iowrite32(reg, ctl + AGNX_INT_MASK); */
/* iowrite32(0x800, ctl + AGNX_CIR_BLKCTL); */
}
} /* agnx_interrupt_ack */
static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
{
struct ieee80211_hw *dev = dev_id;
struct agnx_priv *priv = dev->priv;
void __iomem *ctl = priv->ctl;
irqreturn_t ret = IRQ_NONE;
u32 irq_reason;
spin_lock(&priv->lock);
// printk(KERN_ERR PFX "Get a interrupt %s\n", __func__);
if (priv->init_status != AGNX_START)
goto out;
/* FiXME Here has no lock, Is this will lead to race? */
irq_reason = ioread32(ctl + AGNX_CIR_BLKCTL);
if (!(irq_reason & 0x7))
goto out;
ret = IRQ_HANDLED;
priv->irq_status = ioread32(ctl + AGNX_INT_STAT);
// printk(PFX "Interrupt reason is 0x%x\n", irq_reason);
/* Make sure the txm and txd flags don't conflict with other unknown
interrupt flag, maybe is not necessary */
irq_reason &= 0xF;
disable_rx_interrupt(priv);
/* TODO Make sure the card finished initialized */
agnx_interrupt_ack(priv, &irq_reason);
if ( irq_reason & AGNX_STAT_RX )
handle_rx_irq(priv);
if ( irq_reason & AGNX_STAT_TXD )
handle_txd_irq(priv);
if ( irq_reason & AGNX_STAT_TXM )
handle_txm_irq(priv);
if ( irq_reason & AGNX_STAT_X )
handle_other_irq(priv);
enable_rx_interrupt(priv);
out:
spin_unlock(&priv->lock);
return ret;
} /* agnx_interrupt_handler */
/* FIXME */
static int agnx_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
AGNX_TRACE;
return _agnx_tx(dev->priv, skb);
} /* agnx_tx */
static int agnx_get_mac_address(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
/* Attention! directly read the MAC or other date from EEPROM will
lead to cardbus(WGM511) lock up when write to PM PLL register */
reg = agnx_read32(ctl, 0x3544);
udelay(40);
reg = agnx_read32(ctl, 0x354c);
udelay(50);
/* Get the mac address */
reg = agnx_read32(ctl, 0x3544);
udelay(40);
/* HACK */
reg = cpu_to_le32(reg);
priv->mac_addr[0] = ((u8 *)&reg)[2];
priv->mac_addr[1] = ((u8 *)&reg)[3];
reg = agnx_read32(ctl, 0x3548);
udelay(50);
*((u32 *)(priv->mac_addr + 2)) = cpu_to_le32(reg);
if (!is_valid_ether_addr(priv->mac_addr)) {
DECLARE_MAC_BUF(mbuf);
printk(KERN_WARNING PFX "read mac %s\n", print_mac(mbuf, priv->mac_addr));
printk(KERN_WARNING PFX "Invalid hwaddr! Using random hwaddr\n");
random_ether_addr(priv->mac_addr);
}
return 0;
} /* agnx_get_mac_address */
static int agnx_alloc_rings(struct agnx_priv *priv)
{
unsigned int len;
AGNX_TRACE;
/* Allocate RX/TXM/TXD rings info */
priv->rx.size = AGNX_RX_RING_SIZE;
priv->txm.size = AGNX_TXM_RING_SIZE;
priv->txd.size = AGNX_TXD_RING_SIZE;
len = priv->rx.size + priv->txm.size + priv->txd.size;
// priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL);
priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC);
if (!priv->rx.info)
return -ENOMEM;
priv->txm.info = priv->rx.info + priv->rx.size;
priv->txd.info = priv->txm.info + priv->txm.size;
/* Allocate RX/TXM/TXD descriptors */
priv->rx.desc = pci_alloc_consistent(priv->pdev, sizeof(struct agnx_desc) * len,
&priv->rx.dma);
if (!priv->rx.desc) {
kfree(priv->rx.info);
return -ENOMEM;
}
priv->txm.desc = priv->rx.desc + priv->rx.size;
priv->txm.dma = priv->rx.dma + sizeof(struct agnx_desc) * priv->rx.size;
priv->txd.desc = priv->txm.desc + priv->txm.size;
priv->txd.dma = priv->txm.dma + sizeof(struct agnx_desc) * priv->txm.size;
return 0;
} /* agnx_alloc_rings */
static void rings_free(struct agnx_priv *priv)
{
unsigned int len = priv->rx.size + priv->txm.size + priv->txd.size;
unsigned long flags;
AGNX_TRACE;
spin_lock_irqsave(&priv->lock, flags);
kfree(priv->rx.info);
pci_free_consistent(priv->pdev, sizeof(struct agnx_desc) * len,
priv->rx.desc, priv->rx.dma);
spin_unlock_irqrestore(&priv->lock, flags);
}
static void agnx_periodic_work_handler(struct work_struct *work)
{
struct agnx_priv *priv = container_of(work, struct agnx_priv,
periodic_work.work);
// unsigned long flags;
unsigned long delay;
/* fixme: using mutex?? */
// spin_lock_irqsave(&priv->lock, flags);
/* TODO Recalibrate*/
// calibrate_oscillator(priv);
// antenna_calibrate(priv);
// agnx_send_packet(priv, 997);
/* FIXME */
/* if (debug == 3) */
/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
/* else */
delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY);
// delay = round_jiffies(HZ * 15);
queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay);
// spin_unlock_irqrestore(&priv->lock, flags);
}
static int agnx_start(struct ieee80211_hw *dev)
{
struct agnx_priv *priv = dev->priv;
unsigned long delay;
int err = 0;
AGNX_TRACE;
err = agnx_alloc_rings(priv);
if (err) {
printk(KERN_ERR PFX "Can't alloc RX/TXM/TXD rings\n");
goto out;
}
err = request_irq(priv->pdev->irq, &agnx_interrupt_handler,
IRQF_SHARED, "agnx_pci", dev);
if (err) {
printk(KERN_ERR PFX "Failed to register IRQ handler\n");
rings_free(priv);
goto out;
}
// mdelay(500);
might_sleep();
agnx_hw_init(priv);
// mdelay(500);
might_sleep();
priv->init_status = AGNX_START;
/* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */
/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
/* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */
out:
return err;
} /* agnx_start */
static void agnx_stop(struct ieee80211_hw *dev)
{
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
priv->init_status = AGNX_STOP;
/* make sure hardware will not generate irq */
agnx_hw_reset(priv);
free_irq(priv->pdev->irq, dev);
flush_workqueue(priv->hw->workqueue);
// cancel_delayed_work_sync(&priv->periodic_work);
unfill_rings(priv);
rings_free(priv);
}
static int agnx_config(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct agnx_priv *priv = dev->priv;
int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
AGNX_TRACE;
spin_lock(&priv->lock);
/* FIXME need priv lock? */
if (channel != priv->channel) {
priv->channel = channel;
agnx_set_channel(priv, priv->channel);
}
spin_unlock(&priv->lock);
return 0;
}
static int agnx_config_interface(struct ieee80211_hw *dev,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
{
struct agnx_priv *priv = dev->priv;
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
spin_lock(&priv->lock);
if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
// u32 reghi, reglo;
agnx_set_bssid(priv, conf->bssid);
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
hash_write(priv, conf->bssid, BSSID_STAID);
sta_init(priv, BSSID_STAID);
/* FIXME needed? */
sta_power_init(priv, BSSID_STAID);
agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1);
}
if (conf->ssid_len != priv->ssid_len ||
memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
agnx_set_ssid(priv, conf->ssid, conf->ssid_len);
priv->ssid_len = conf->ssid_len;
memcpy(priv->ssid, conf->ssid, conf->ssid_len);
}
spin_unlock(&priv->lock);
return 0;
} /* agnx_config_interface */
static void agnx_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_mc_list *mclist)
{
unsigned int new_flags = 0;
*total_flags = new_flags;
/* TODO */
}
static int agnx_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
spin_lock(&priv->lock);
/* FIXME */
if (priv->mode != NL80211_IFTYPE_MONITOR)
return -EOPNOTSUPP;
switch (conf->type) {
case NL80211_IFTYPE_STATION:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
spin_unlock(&priv->lock);
return 0;
}
static void agnx_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
/* TODO */
priv->mode = NL80211_IFTYPE_MONITOR;
}
static int agnx_get_stats(struct ieee80211_hw *dev,
struct ieee80211_low_level_stats *stats)
{
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
spin_lock(&priv->lock);
/* TODO !! */
memcpy(stats, &priv->stats, sizeof(*stats));
spin_unlock(&priv->lock);
return 0;
}
static u64 agnx_get_tsft(struct ieee80211_hw *dev)
{
void __iomem *ctl = ((struct agnx_priv *)dev->priv)->ctl;
u32 tsftl;
u64 tsft;
AGNX_TRACE;
/* FIXME */
tsftl = ioread32(ctl + AGNX_TXM_TIMESTAMPLO);
tsft = ioread32(ctl + AGNX_TXM_TIMESTAMPHI);
tsft <<= 32;
tsft |= tsftl;
return tsft;
}
static int agnx_get_tx_stats(struct ieee80211_hw *dev,
struct ieee80211_tx_queue_stats *stats)
{
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
/* FIXME now we just using txd queue, but should using txm queue too */
stats[0].len = (priv->txd.idx - priv->txd.idx_sent) / 2;
stats[0].limit = priv->txd.size - 2;
stats[0].count = priv->txd.idx / 2;
return 0;
}
static struct ieee80211_ops agnx_ops = {
.tx = agnx_tx,
.start = agnx_start,
.stop = agnx_stop,
.add_interface = agnx_add_interface,
.remove_interface = agnx_remove_interface,
.config = agnx_config,
.config_interface = agnx_config_interface,
.configure_filter = agnx_configure_filter,
.get_stats = agnx_get_stats,
.get_tx_stats = agnx_get_tx_stats,
.get_tsf = agnx_get_tsft
};
static void __devexit agnx_pci_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct agnx_priv *priv = dev->priv;
AGNX_TRACE;
if (!dev)
return;
ieee80211_unregister_hw(dev);
pci_iounmap(pdev, priv->ctl);
pci_iounmap(pdev, priv->data);
pci_release_regions(pdev);
pci_disable_device(pdev);
ieee80211_free_hw(dev);
}
static int __devinit agnx_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ieee80211_hw *dev;
struct agnx_priv *priv;
u32 mem_addr0, mem_len0;
u32 mem_addr1, mem_len1;
int err;
DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR PFX "Can't enable new PCI device\n");
return err;
}
/* get pci resource */
mem_addr0 = pci_resource_start(pdev, 0);
mem_len0 = pci_resource_len(pdev, 0);
mem_addr1 = pci_resource_start(pdev, 1);
mem_len1 = pci_resource_len(pdev, 1);
printk(KERN_DEBUG PFX "Memaddr0 is %x, length is %x\n", mem_addr0, mem_len0);
printk(KERN_DEBUG PFX "Memaddr1 is %x, length is %x\n", mem_addr1, mem_len1);
err = pci_request_regions(pdev, "agnx-pci");
if (err) {
printk(KERN_ERR PFX "Can't obtain PCI resource\n");
return err;
}
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR PFX "No suitable DMA available\n");
goto err_free_reg;
}
pci_set_master(pdev);
printk(KERN_DEBUG PFX "pdev->irq is %d\n", pdev->irq);
dev = ieee80211_alloc_hw(sizeof(*priv), &agnx_ops);
if (!dev) {
printk(KERN_ERR PFX "ieee80211 alloc failed\n");
err = -ENOMEM;
goto err_free_reg;
}
/* init priv */
priv = dev->priv;
memset(priv, 0, sizeof(*priv));
priv->mode = NL80211_IFTYPE_MONITOR;
priv->pdev = pdev;
priv->hw = dev;
spin_lock_init(&priv->lock);
priv->init_status = AGNX_UNINIT;
/* Map mem #1 and #2 */
priv->ctl = pci_iomap(pdev, 0, mem_len0);
// printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl);
if (!priv->ctl) {
printk(KERN_ERR PFX "Can't map device memory\n");
goto err_free_dev;
}
priv->data = pci_iomap(pdev, 1, mem_len1);
printk(KERN_DEBUG PFX "MEM2 mapped address is 0x%p\n", priv->data);
if (!priv->data) {
printk(KERN_ERR PFX "Can't map device memory\n");
goto err_iounmap2;
}
pci_read_config_byte(pdev, PCI_REVISION_ID, &priv->revid);
priv->band.channels = (struct ieee80211_channel *)agnx_channels;
priv->band.n_channels = ARRAY_SIZE(agnx_channels);
priv->band.bitrates = (struct ieee80211_rate *)agnx_rates_80211g;
priv->band.n_bitrates = ARRAY_SIZE(agnx_rates_80211g);
/* Init ieee802.11 dev */
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
dev->extra_tx_headroom = sizeof(struct agnx_hdr);
/* FIXME It only include FCS in promious mode but not manage mode */
/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */
dev->channel_change_time = 5000;
dev->max_signal = 100;
/* FIXME */
dev->queues = 1;
agnx_get_mac_address(priv);
SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr);
/* /\* FIXME *\/ */
/* for (i = 1; i < NUM_DRIVE_MODES; i++) { */
/* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */
/* if (err) { */
/* printk(KERN_ERR PFX "Can't register hwmode\n"); */
/* goto err_iounmap; */
/* } */
/* } */
priv->channel = 1;
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
err = ieee80211_register_hw(dev);
if (err) {
printk(KERN_ERR PFX "Can't register hardware\n");
goto err_iounmap;
}
agnx_hw_reset(priv);
printk(PFX "%s: hwaddr %s, Rev 0x%02x\n", wiphy_name(dev->wiphy),
print_mac(mac, dev->wiphy->perm_addr), priv->revid);
return 0;
err_iounmap:
pci_iounmap(pdev, priv->data);
err_iounmap2:
pci_iounmap(pdev, priv->ctl);
err_free_dev:
pci_set_drvdata(pdev, NULL);
ieee80211_free_hw(dev);
err_free_reg:
pci_release_regions(pdev);
pci_disable_device(pdev);
return err;
} /* agnx_pci_probe*/
#ifdef CONFIG_PM
static int agnx_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
AGNX_TRACE;
ieee80211_stop_queues(dev);
agnx_stop(dev);
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
static int agnx_pci_resume(struct pci_dev *pdev)
{
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
AGNX_TRACE;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
agnx_start(dev);
ieee80211_wake_queues(dev);
return 0;
}
#else
#define agnx_pci_suspend NULL
#define agnx_pci_resume NULL
#endif /* CONFIG_PM */
static struct pci_driver agnx_pci_driver = {
.name = "agnx-pci",
.id_table = agnx_pci_id_tbl,
.probe = agnx_pci_probe,
.remove = __devexit_p(agnx_pci_remove),
.suspend = agnx_pci_suspend,
.resume = agnx_pci_resume,
};
static int __init agnx_pci_init(void)
{
AGNX_TRACE;
return pci_register_driver(&agnx_pci_driver);
}
static void __exit agnx_pci_exit(void)
{
AGNX_TRACE;
pci_unregister_driver(&agnx_pci_driver);
}
module_init(agnx_pci_init);
module_exit(agnx_pci_exit);

958
drivers/staging/agnx/phy.c Normal file
View File

@ -0,0 +1,958 @@
/**
* Airgo MIMO wireless driver
*
* Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
* Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
* works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "phy.h"
#include "table.h"
#include "sta.h"
#include "xmit.h"
u8 read_from_eeprom(struct agnx_priv *priv, u16 address)
{
void __iomem *ctl = priv->ctl;
struct agnx_eeprom cmd;
u32 reg;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = EEPROM_CMD_READ << AGNX_EEPROM_COMMAND_SHIFT;
cmd.address = address;
/* Verify that the Status bit is clear */
/* Read Command and Address are written to the Serial Interface */
iowrite32(*(__le32 *)&cmd, ctl + AGNX_CIR_SERIALITF);
/* Wait for the Status bit to clear again */
eeprom_delay();
/* Read from Data */
reg = ioread32(ctl + AGNX_CIR_SERIALITF);
cmd = *(struct agnx_eeprom *)&reg;
return cmd.data;
}
static int card_full_reset(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x80);
reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
return 0;
}
inline void enable_power_saving(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg &= ~0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
}
inline void disable_power_saving(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
}
void disable_receiver(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
/* FIXME Disable the receiver */
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0);
/* Set gain control reset */
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
/* Reset gain control reset */
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
}
/* Fixme this shoule be disable RX, above is enable RX */
void enable_receiver(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
/* Set adaptive gain control discovery mode */
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
/* Set gain control reset */
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
/* Clear gain control reset */
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
}
static void mac_address_set(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u8 *mac_addr = priv->mac_addr;
u32 reg;
/* FIXME */
reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3];
iowrite32(reg, ctl + AGNX_RXM_MACHI);
reg = (mac_addr[4] << 8) | mac_addr[5];
iowrite32(reg, ctl + AGNX_RXM_MACLO);
}
static void receiver_bssid_set(struct agnx_priv *priv, u8 *bssid)
{
void __iomem *ctl = priv->ctl;
u32 reg;
disable_receiver(priv);
/* FIXME */
reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3];
iowrite32(reg, ctl + AGNX_RXM_BSSIDHI);
reg = (bssid[4] << 8) | bssid[5];
iowrite32(reg, ctl + AGNX_RXM_BSSIDLO);
/* Enable the receiver */
enable_receiver(priv);
/* Clear the TSF */
/* agnx_write32(ctl, AGNX_TXM_TSFLO, 0x0); */
/* agnx_write32(ctl, AGNX_TXM_TSFHI, 0x0); */
/* Clear the TBTT */
agnx_write32(ctl, AGNX_TXM_TBTTLO, 0x0);
agnx_write32(ctl, AGNX_TXM_TBTTHI, 0x0);
disable_receiver(priv);
} /* receiver_bssid_set */
static void band_management_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
void __iomem *data = priv->data;
u32 reg;
int i;
AGNX_TRACE;
agnx_write32(ctl, AGNX_BM_TXWADDR, AGNX_PDU_TX_WQ);
agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0);
memset_io(data + AGNX_PDUPOOL, 0x0, AGNX_PDUPOOL_SIZE);
agnx_write32(ctl, AGNX_BM_BMCTL, 0x200);
agnx_write32(ctl, AGNX_BM_CIPDUWCNT, 0x40);
agnx_write32(ctl, AGNX_BM_SPPDUWCNT, 0x2);
agnx_write32(ctl, AGNX_BM_RFPPDUWCNT, 0x0);
agnx_write32(ctl, AGNX_BM_RHPPDUWCNT, 0x22);
/* FIXME Initialize the Free Pool Linked List */
/* 1. Write the Address of the Next Node ((0x41800 + node*size)/size)
to the first word of each node. */
for (i = 0; i < PDU_FREE_CNT; i++) {
iowrite32((AGNX_PDU_FREE + (i+1)*PDU_SIZE)/PDU_SIZE,
data + AGNX_PDU_FREE + (PDU_SIZE * i));
/* The last node should be set to 0x0 */
if ((i + 1) == PDU_FREE_CNT)
memset_io(data + AGNX_PDU_FREE + (PDU_SIZE * i),
0x0, PDU_SIZE);
}
/* Head is First Pool address (0x41800) / size (0x80) */
agnx_write32(ctl, AGNX_BM_FPLHP, AGNX_PDU_FREE/PDU_SIZE);
/* Tail is Last Pool Address (0x47f80) / size (0x80) */
agnx_write32(ctl, AGNX_BM_FPLTP, 0x47f80/PDU_SIZE);
/* Count is Number of Nodes in the Pool (0xd0) */
agnx_write32(ctl, AGNX_BM_FPCNT, PDU_FREE_CNT);
/* Start all workqueue */
agnx_write32(ctl, AGNX_BM_CIWQCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_CPULWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_CPUHWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_CPUTXWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_CPURXWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_SPRXWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_SPTXWCTL, 0x80000);
agnx_write32(ctl, AGNX_BM_RFPWCTL, 0x80000);
/* Enable the Band Management */
reg = agnx_read32(ctl, AGNX_BM_BMCTL);
reg |= 0x1;
agnx_write32(ctl, AGNX_BM_BMCTL, reg);
} /* band_managment_init */
static void system_itf_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x0);
agnx_write32(ctl, AGNX_PM_TESTPHY, 0x11e143a);
if (priv->revid == 0) {
reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE);
reg |= 0x11;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg);
}
/* ??? What is that means? it should difference for differice type
of cards */
agnx_write32(ctl, AGNX_CIR_SERIALITF, 0xfff81006);
agnx_write32(ctl, AGNX_SYSITF_GPIOIN, 0x1f0000);
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN);
}
static void encryption_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
agnx_write32(ctl, AGNX_ENCRY_WEPKEY0, 0x0);
agnx_write32(ctl, AGNX_ENCRY_WEPKEY1, 0x0);
agnx_write32(ctl, AGNX_ENCRY_WEPKEY2, 0x0);
agnx_write32(ctl, AGNX_ENCRY_WEPKEY3, 0x0);
agnx_write32(ctl, AGNX_ENCRY_CCMRECTL, 0x8);
}
static void tx_management_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
void __iomem *data = priv->data;
u32 reg;
AGNX_TRACE;
/* Fill out the ComputationalEngineLookupTable
* starting at memory #2 offset 0x800
*/
tx_engine_lookup_tbl_init(priv);
memset_io(data + 0x1000, 0, 0xfe0);
/* Enable Transmission Management Functions */
agnx_write32(ctl, AGNX_TXM_ETMF, 0x3ff);
/* Write 0x3f to Transmission Template */
agnx_write32(ctl, AGNX_TXM_TXTEMP, 0x3f);
if (priv->revid >= 2)
agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e140a0b);
else
agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e190a0b);
reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
reg &= 0xff00;
reg |= 0xb;
agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
reg &= 0xffff00ff;
reg |= 0xa00;
agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
/* Enable TIFS */
agnx_write32(ctl, AGNX_TXM_CTL, 0x40000);
reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
reg &= 0xff00ffff;
reg |= 0x510000;
agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
reg &= 0xff00ffff;
agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
reg &= 0x00ffffff;
reg |= 0x1c000000;
agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
reg &= 0x00ffffff;
reg |= 0x01000000;
agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
/* # Set DIF 0-1,2-3,4-5,6-7 to defaults */
agnx_write32(ctl, AGNX_TXM_DIF01, 0x321d321d);
agnx_write32(ctl, AGNX_TXM_DIF23, 0x321d321d);
agnx_write32(ctl, AGNX_TXM_DIF45, 0x321d321d);
agnx_write32(ctl, AGNX_TXM_DIF67, 0x321d321d);
/* Max Ack timeout limit */
agnx_write32(ctl, AGNX_TXM_MAXACKTIM, 0x1e19);
/* Max RX Data Timeout count, */
reg = agnx_read32(ctl, AGNX_TXM_MAXRXTIME);
reg &= 0xffff0000;
reg |= 0xff;
agnx_write32(ctl, AGNX_TXM_MAXRXTIME, reg);
/* CF poll RX Timeout count */
reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
reg &= 0xffff;
reg |= 0xff0000;
agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
/* Max Timeout Exceeded count, */
reg = agnx_read32(ctl, AGNX_TXM_MAXTIMOUT);
reg &= 0xff00ffff;
reg |= 0x190000;
agnx_write32(ctl, AGNX_TXM_MAXTIMOUT, reg);
/* CF ack timeout limit for 11b */
reg = agnx_read32(ctl, AGNX_TXM_CFACKT11B);
reg &= 0xff00;
reg |= 0x1e;
agnx_write32(ctl, AGNX_TXM_CFACKT11B, reg);
/* Max CF Poll Timeout Count */
reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
reg &= 0xffff0000;
reg |= 0x19;
agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
/* CF Poll RX Timeout Count */
reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
reg &= 0xffff0000;
reg |= 0x1e;
agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
/* # write default to */
/* 1. Schedule Empty Count */
agnx_write32(ctl, AGNX_TXM_SCHEMPCNT, 0x5);
/* 2. CFP Period Count */
agnx_write32(ctl, AGNX_TXM_CFPERCNT, 0x1);
/* 3. CFP MDV */
agnx_write32(ctl, AGNX_TXM_CFPMDV, 0x10000);
/* Probe Delay */
reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
reg &= 0xffff0000;
reg |= 0x400;
agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
/* Max CCA count Slot */
reg = agnx_read32(ctl, AGNX_TXM_MAXCCACNTSLOT);
reg &= 0xffff00ff;
reg |= 0x900;
agnx_write32(ctl, AGNX_TXM_MAXCCACNTSLOT, reg);
/* Slot limit/1 msec Limit */
reg = agnx_read32(ctl, AGNX_TXM_SLOTLIMIT);
reg &= 0xff00ffff;
reg |= 0x140077;
agnx_write32(ctl, AGNX_TXM_SLOTLIMIT, reg);
/* # Set CW #(0-7) to default */
agnx_write32(ctl, AGNX_TXM_CW0, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW1, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW2, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW3, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW4, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW5, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW6, 0xff0007);
agnx_write32(ctl, AGNX_TXM_CW7, 0xff0007);
/* # Set Short/Long limit #(0-7) to default */
agnx_write32(ctl, AGNX_TXM_SLBEALIM0, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM1, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM2, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM3, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM4, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM5, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM6, 0xa000a);
agnx_write32(ctl, AGNX_TXM_SLBEALIM7, 0xa000a);
reg = agnx_read32(ctl, AGNX_TXM_CTL);
reg |= 0x1400;
agnx_write32(ctl, AGNX_TXM_CTL, reg);
/* Wait for bit 0 in Control Reg to clear */
udelay(80);
reg = agnx_read32(ctl, AGNX_TXM_CTL);
/* Or 0x18000 to Control reg */
reg = agnx_read32(ctl, AGNX_TXM_CTL);
reg |= 0x18000;
agnx_write32(ctl, AGNX_TXM_CTL, reg);
/* Wait for bit 0 in Control Reg to clear */
udelay(80);
reg = agnx_read32(ctl, AGNX_TXM_CTL);
/* Set Listen Interval Count to default */
agnx_write32(ctl, AGNX_TXM_LISINTERCNT, 0x1);
/* Set DTIM period count to default */
agnx_write32(ctl, AGNX_TXM_DTIMPERICNT, 0x2000);
} /* tx_management_init */
static void rx_management_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
/* Initialize the Routing Table */
routing_table_init(priv);
if (priv->revid >= 3) {
agnx_write32(ctl, 0x2074, 0x1f171710);
agnx_write32(ctl, 0x2078, 0x10100d0d);
agnx_write32(ctl, 0x207c, 0x11111010);
}
else
agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0);
agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00);
}
static void agnx_timer_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
AGNX_TRACE;
/* /\* Write 0x249f00 (tick duration?) to Timer 1 *\/ */
/* agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x249f00); */
/* /\* Write 0xe2 to Timer 1 Control *\/ */
/* agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0xe2); */
/* Write 0x249f00 (tick duration?) to Timer 1 */
agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x0);
/* Write 0xe2 to Timer 1 Control */
agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0x0);
iowrite32(0xFFFFFFFF, priv->ctl + AGNX_TXM_BEACON_CTL);
}
static void power_manage_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
agnx_write32(ctl, AGNX_PM_MACMSW, 0x1f);
agnx_write32(ctl, AGNX_PM_RFCTL, 0x1f);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg &= 0xf00f;
reg |= 0xa0;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
if (priv->revid >= 3) {
reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
reg |= 0x18;
agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
}
} /* power_manage_init */
static void gain_ctlcnt_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
agnx_write32(ctl, AGNX_GCR_TRACNT5, 0x119);
agnx_write32(ctl, AGNX_GCR_TRACNT6, 0x118);
agnx_write32(ctl, AGNX_GCR_TRACNT7, 0x117);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg &= ~0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0);
/* FIXME Write the initial Station Descriptor for the card */
sta_init(priv, LOCAL_STAID);
sta_init(priv, BSSID_STAID);
/* Enable staion 0 and 1 can do TX */
/* It seemed if we set other bit to 1 the bit 0 will
be auto change to 0 */
agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1);
// agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1);
} /* gain_ctlcnt_init */
static void phy_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
void __iomem *data = priv->data;
u32 reg;
AGNX_TRACE;
/* Load InitialGainTable */
gain_table_init(priv);
agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x2000000);
/* Clear the following offsets in Memory Range #2: */
memset_io(data + 0x5040, 0, 0xa * 4);
memset_io(data + 0x5080, 0, 0xa * 4);
memset_io(data + 0x50c0, 0, 0xa * 4);
memset_io(data + 0x5400, 0, 0x80 * 4);
memset_io(data + 0x6000, 0, 0x280 * 4);
memset_io(data + 0x7000, 0, 0x280 * 4);
memset_io(data + 0x8000, 0, 0x280 * 4);
/* Initialize the Following Registers According to PCI Revision ID */
if (priv->revid == 0) {
/* fixme the part hasn't been update but below has been update
based on WGM511 */
agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x1d);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x3);
agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11);
agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0);
agnx_write32(ctl, AGNX_GCR_THD0A, 0x64);
agnx_write32(ctl, AGNX_GCR_THD0AL, 0x4b);
agnx_write32(ctl, AGNX_GCR_THD0B, 0x4b);
agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14);
agnx_write32(ctl, AGNX_GCR_DSAT, 0x24);
agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8);
agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a);
agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3);
agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd);
agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1);
agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7);
agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28);
agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
reg = agnx_read32(ctl, AGNX_GCR_CWDETEC);
reg |= 0x1;
agnx_write32(ctl, AGNX_GCR_CWDETEC, reg);
agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3);
agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x0);
agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x0);
agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x0);
agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x0);
agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10);
agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1);
agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0x1);
agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190);
agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x78);
agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x1c);
agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0);
agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x1);
agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0);
agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f);
agnx_write32(ctl, AGNX_GCR_THJUMP, 0x14);
agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0);
agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x30);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x32);
agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19);
agnx_write32(ctl, AGNX_GCR_0X14c, 0x0);
agnx_write32(ctl, AGNX_GCR_0X150, 0x0);
agnx_write32(ctl, 0x9400, 0x0);
agnx_write32(ctl, 0x940c, 0x6ff);
agnx_write32(ctl, 0x9428, 0xa0);
agnx_write32(ctl, 0x9434, 0x0);
agnx_write32(ctl, 0x9c04, 0x15);
agnx_write32(ctl, 0x9c0c, 0x7f);
agnx_write32(ctl, 0x9c34, 0x0);
agnx_write32(ctl, 0xc000, 0x38d);
agnx_write32(ctl, 0x14018, 0x0);
agnx_write32(ctl, 0x16000, 0x1);
agnx_write32(ctl, 0x11004, 0x0);
agnx_write32(ctl, 0xec54, 0xa);
agnx_write32(ctl, 0xec1c, 0x5);
} else if (priv->revid > 0) {
agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11);
agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0);
agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14);
agnx_write32(ctl, AGNX_GCR_DSAT, 0x24);
agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8);
agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a);
agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3);
agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd);
agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1);
agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7);
agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28);
agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
agnx_write32(ctl, AGNX_GCR_CWDETEC, 0x0);
agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
// agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x32);
agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x32);
agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x32);
agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x32);
agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10);
agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1ad);
agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0xa10);
agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190);
agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0);
agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
agnx_write32(ctl, AGNX_GCR_THCS, 0x0);
agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x4);
agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0);
agnx_write32(ctl, AGNX_GCR_THJUMP, 0x1e);
agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0);
agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x2a);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c);
agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19);
agnx_write32(ctl, AGNX_GCR_0X14c, 0x0);
agnx_write32(ctl, AGNX_GCR_0X150, 0x0);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
agnx_write32(ctl, AGNX_GCR_WATCHDOG, 0x37);
agnx_write32(ctl, 0x9400, 0x0);
agnx_write32(ctl, 0x940c, 0x6ff);
agnx_write32(ctl, 0x9428, 0xa0);
agnx_write32(ctl, 0x9434, 0x0);
agnx_write32(ctl, 0x9c04, 0x15);
agnx_write32(ctl, 0x9c0c, 0x7f);
agnx_write32(ctl, 0x9c34, 0x0);
agnx_write32(ctl, 0xc000, 0x38d);
agnx_write32(ctl, 0x14014, 0x1000);
agnx_write32(ctl, 0x14018, 0x0);
agnx_write32(ctl, 0x16000, 0x1);
agnx_write32(ctl, 0x11004, 0x0);
agnx_write32(ctl, 0xec54, 0xa);
agnx_write32(ctl, 0xec1c, 0x50);
} else if (priv->revid > 1) {
reg = agnx_read32(ctl, 0xec18);
reg |= 0x8;
agnx_write32(ctl, 0xec18, reg);
}
/* Write the TX Fir Coefficient Table */
tx_fir_table_init(priv);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg &= ~0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
reg |= 0x1;
agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
/* reg = agnx_read32(ctl, 0x1a030); */
/* reg &= ~0x4; */
/* agnx_write32(ctl, 0x1a030, reg); */
agnx_write32(ctl, AGNX_GCR_TRACNT4, 0x113);
} /* phy_init */
static void chip_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
band_management_init(priv);
rf_chips_init(priv);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
/* Initialize the PHY */
phy_init(priv);
encryption_init(priv);
tx_management_init(priv);
rx_management_init(priv);
power_manage_init(priv);
/* Initialize the Timers */
agnx_timer_init(priv);
/* Write 0xc390bf9 to Interrupt Mask (Disable TX) */
reg = 0xc390bf9 & ~IRQ_TX_BEACON;
reg &= ~IRQ_TX_DISABLE;
agnx_write32(ctl, AGNX_INT_MASK, reg);
reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
reg |= 0x800;
agnx_write32(ctl, AGNX_CIR_BLKCTL, reg);
/* set it when need get multicast enable? */
agnx_write32(ctl, AGNX_BM_MTSM, 0xff);
} /* chip_init */
static inline void set_promis_and_managed(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2);
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2);
}
static inline void set_learn_mode(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x8);
}
static inline void set_scan_mode(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x20);
}
static inline void set_promiscuous_mode(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
/* agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x210);*/
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10);
}
static inline void set_managed_mode(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x2);
}
static inline void set_adhoc_mode(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x0);
}
static void unknow_register_write(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x0, 0x3e);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4, 0xb2);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x8, 0x140);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0xc, 0x1C0);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x10, 0x1FF);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x14, 0x1DD);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x18, 0x15F);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x1c, 0xA1);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x20, 0x3E7);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x24, 0x36B);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x28, 0x348);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x2c, 0x37D);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x30, 0x3DE);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x34, 0x36);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x38, 0x64);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x3c, 0x57);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x40, 0x23);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x44, 0x3ED);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x48, 0x3C9);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4c, 0x3CA);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x50, 0x3E7);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x54, 0x8);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x58, 0x1F);
agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x5c, 0x1a);
}
static void card_interface_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u8 bssid[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u32 reg;
unsigned int i;
AGNX_TRACE;
might_sleep();
/* Clear RX Control and Enable RX queues */
agnx_write32(ctl, AGNX_CIR_RXCTL, 0x8);
might_sleep();
/* Do a full reset of the card */
card_full_reset(priv);
might_sleep();
/* Check and set Card Endianness */
reg = ioread32(priv->ctl + AGNX_CIR_ENDIAN);
/* TODO If not 0xB3B2B1B0 set to 0xB3B2B1B0 */
printk(KERN_INFO PFX "CIR_ENDIAN is %x\n", reg);
/* Config the eeprom */
agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x7000086);
udelay(10);
reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033);
reg = agnx_read32(ctl, 0xec50);
reg |= 0xf;
agnx_write32(ctl, 0xec50, reg);
agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN);
udelay(10);
reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
/* Dump the eeprom */
do {
char eeprom[0x100000/0x100];
for (i = 0; i < 0x100000; i += 0x100) {
agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x3000000 + i);
udelay(13);
reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
udelay(70);
reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
eeprom[i/0x100] = reg & 0xFF;
udelay(10);
}
print_hex_dump_bytes(PFX "EEPROM: ", DUMP_PREFIX_NONE, eeprom,
ARRAY_SIZE(eeprom));
} while(0);
spi_rc_write(ctl, RF_CHIP0, 0x26);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
/* Initialize the system interface */
system_itf_init(priv);
might_sleep();
/* Chip Initialization (Polaris) */
chip_init(priv);
might_sleep();
/* Calibrate the antennae */
antenna_calibrate(priv);
reg = agnx_read32(ctl, 0xec50);
reg &= ~0x40;
agnx_write32(ctl, 0xec50, reg);
agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
agnx_write32(ctl, AGNX_PM_PLLCTL, 0x1);
reg = agnx_read32(ctl, AGNX_BM_BMCTL);
reg |= 0x8000;
agnx_write32(ctl, AGNX_BM_BMCTL, reg);
enable_receiver(priv);
reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE);
reg |= 0x200;
agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg);
enable_receiver(priv);
might_sleep();
/* Initialize Gain Control Counts */
gain_ctlcnt_init(priv);
/* Write Initial Station Power Template for this station(#0) */
sta_power_init(priv, LOCAL_STAID);
might_sleep();
/* Initialize the rx,td,tm rings, for each node in the ring */
fill_rings(priv);
might_sleep();
agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033);
agnx_write32(ctl, 0xec50, 0xc);
agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
/* FIXME Initialize the transmit control register */
agnx_write32(ctl, AGNX_TXM_CTL, 0x194c1);
enable_receiver(priv);
might_sleep();
/* FIXME Set the Receive Control Mac Address to card address */
mac_address_set(priv);
enable_receiver(priv);
might_sleep();
/* Set the recieve request rate */
/* FIXME Enable the request */
/* Check packet length */
/* Set maximum packet length */
/* agnx_write32(ctl, AGNX_RXM_REQRATE, 0x88195e00); */
/* enable_receiver(priv); */
/* Set the Receiver BSSID */
receiver_bssid_set(priv, bssid);
/* FIXME Set to managed mode */
set_managed_mode(priv);
// set_promiscuous_mode(priv);
/* set_scan_mode(priv); */
/* set_learn_mode(priv); */
// set_promis_and_managed(priv);
// set_adhoc_mode(priv);
/* Set the recieve request rate */
/* Check packet length */
agnx_write32(ctl, AGNX_RXM_REQRATE, 0x08000000);
reg = agnx_read32(ctl, AGNX_RXM_REQRATE);
/* Set maximum packet length */
reg |= 0x00195e00;
agnx_write32(ctl, AGNX_RXM_REQRATE, reg);
/* Configure the RX and TX interrupt */
reg = ENABLE_RX_INTERRUPT | RX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE;
agnx_write32(ctl, AGNX_CIR_RXCFG, reg);
/* FIXME */
reg = ENABLE_TX_INTERRUPT | TX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE;
agnx_write32(ctl, AGNX_CIR_TXCFG, reg);
/* Enable RX TX Interrupts */
agnx_write32(ctl, AGNX_CIR_RXCTL, 0x80);
agnx_write32(ctl, AGNX_CIR_TXMCTL, 0x80);
agnx_write32(ctl, AGNX_CIR_TXDCTL, 0x80);
/* FIXME Set the master control interrupt in block control */
agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x800);
/* Enable RX and TX queues */
reg = agnx_read32(ctl, AGNX_CIR_RXCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_CIR_RXCTL, reg);
reg = agnx_read32(ctl, AGNX_CIR_TXMCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_CIR_TXMCTL, reg);
reg = agnx_read32(ctl, AGNX_CIR_TXDCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_CIR_TXDCTL, reg);
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
/* FIXME */
/* unknow_register_write(priv); */
/* Update local card hash entry */
hash_write(priv, priv->mac_addr, LOCAL_STAID);
might_sleep();
/* FIXME */
agnx_set_channel(priv, 1);
might_sleep();
} /* agnx_card_interface_init */
void agnx_hw_init(struct agnx_priv *priv)
{
AGNX_TRACE;
might_sleep();
card_interface_init(priv);
}
int agnx_hw_reset(struct agnx_priv *priv)
{
return card_full_reset(priv);
}
int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len)
{
AGNX_TRACE;
return 0;
}
void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid)
{
receiver_bssid_set(priv, bssid);
}

409
drivers/staging/agnx/phy.h Normal file
View File

@ -0,0 +1,409 @@
#ifndef AGNX_PHY_H_
#define AGNX_PHY_H_
#include "agnx.h"
/* Transmission Managment Registers */
#define AGNX_TXM_BASE 0x0000
#define AGNX_TXM_CTL 0x0000 /* control register */
#define AGNX_TXM_ETMF 0x0004 /* enable transmission management functions */
#define AGNX_TXM_TXTEMP 0x0008 /* transmission template */
#define AGNX_TXM_RETRYSTAID 0x000c /* Retry Station ID */
#define AGNX_TXM_TIMESTAMPLO 0x0010 /* Timestamp Lo */
#define AGNX_TXM_TIMESTAMPHI 0x0014 /* Timestamp Hi */
#define AGNX_TXM_TXDELAY 0x0018 /* tx delay */
#define AGNX_TXM_TBTTLO 0x0020 /* tbtt Lo */
#define AGNX_TXM_TBTTHI 0x0024 /* tbtt Hi */
#define AGNX_TXM_BEAINTER 0x0028 /* Beacon Interval */
#define AGNX_TXM_NAV 0x0030 /* NAV */
#define AGNX_TXM_CFPMDV 0x0034 /* CFP MDV */
#define AGNX_TXM_CFPERCNT 0x0038 /* CFP period count */
#define AGNX_TXM_PROBDELAY 0x003c /* probe delay */
#define AGNX_TXM_LISINTERCNT 0x0040 /* listen interval count */
#define AGNX_TXM_DTIMPERICNT 0x004c /* DTIM period count */
#define AGNX_TXM_BEACON_CTL 0x005c /* beacon control */
#define AGNX_TXM_SCHEMPCNT 0x007c /* schedule empty count */
#define AGNX_TXM_MAXTIMOUT 0x0084 /* max timeout exceed count */
#define AGNX_TXM_MAXCFPTIM 0x0088 /* max CF poll timeout count */
#define AGNX_TXM_MAXRXTIME 0x008c /* max RX timeout count */
#define AGNX_TXM_MAXACKTIM 0x0090 /* max ACK timeout count */
#define AGNX_TXM_DIF01 0x00a0 /* DIF 0-1 */
#define AGNX_TXM_DIF23 0x00a4 /* DIF 2-3 */
#define AGNX_TXM_DIF45 0x00a8 /* DIF 4-5 */
#define AGNX_TXM_DIF67 0x00ac /* DIF 6-7 */
#define AGNX_TXM_SIFSPIFS 0x00b0 /* SIFS/PIFS */
#define AGNX_TXM_TIFSEIFS 0x00b4 /* TIFS/EIFS */
#define AGNX_TXM_MAXCCACNTSLOT 0x00b8 /* max CCA count slot */
#define AGNX_TXM_SLOTLIMIT 0x00bc /* slot limit/1 msec limit */
#define AGNX_TXM_CFPOLLRXTIM 0x00f0 /* CF poll RX timeout count */
#define AGNX_TXM_CFACKT11B 0x00f4 /* CF ack timeout limit for 11b */
#define AGNX_TXM_CW0 0x0100 /* CW 0 */
#define AGNX_TXM_SLBEALIM0 0x0108 /* short/long beacon limit 0 */
#define AGNX_TXM_CW1 0x0120 /* CW 1 */
#define AGNX_TXM_SLBEALIM1 0x0128 /* short/long beacon limit 1 */
#define AGNX_TXM_CW2 0x0140 /* CW 2 */
#define AGNX_TXM_SLBEALIM2 0x0148 /* short/long beacon limit 2 */
#define AGNX_TXM_CW3 0x0160 /* CW 3 */
#define AGNX_TXM_SLBEALIM3 0x0168 /* short/long beacon limit 3 */
#define AGNX_TXM_CW4 0x0180 /* CW 4 */
#define AGNX_TXM_SLBEALIM4 0x0188 /* short/long beacon limit 4 */
#define AGNX_TXM_CW5 0x01a0 /* CW 5 */
#define AGNX_TXM_SLBEALIM5 0x01a8 /* short/long beacon limit 5 */
#define AGNX_TXM_CW6 0x01c0 /* CW 6 */
#define AGNX_TXM_SLBEALIM6 0x01c8 /* short/long beacon limit 6 */
#define AGNX_TXM_CW7 0x01e0 /* CW 7 */
#define AGNX_TXM_SLBEALIM7 0x01e8 /* short/long beacon limit 7 */
#define AGNX_TXM_BEACONTEMP 0x1000 /* beacon template */
#define AGNX_TXM_STAPOWTEMP 0x1a00 /* Station Power Template */
/* Receive Management Control Registers */
#define AGNX_RXM_BASE 0x2000
#define AGNX_RXM_REQRATE 0x2000 /* requested rate */
#define AGNX_RXM_MACHI 0x2004 /* first 4 bytes of mac address */
#define AGNX_RXM_MACLO 0x2008 /* last 2 bytes of mac address */
#define AGNX_RXM_BSSIDHI 0x200c /* bssid hi */
#define AGNX_RXM_BSSIDLO 0x2010 /* bssid lo */
#define AGNX_RXM_HASH_CMD_FLAG 0x2014 /* Flags for the RX Hash Command Default:0 */
#define AGNX_RXM_HASH_CMD_HIGH 0x2018 /* The High half of the Hash Command */
#define AGNX_RXM_HASH_CMD_LOW 0x201c /* The Low half of the Hash Command */
#define AGNX_RXM_ROUTAB 0x2020 /* routing table */
#define ROUTAB_SUBTYPE_SHIFT 24
#define ROUTAB_TYPE_SHIFT 28
#define ROUTAB_STATUS_SHIFT 30
#define ROUTAB_RW_SHIFT 31
#define ROUTAB_ROUTE_DROP 0xf00000 /* Drop */
#define ROUTAB_ROUTE_CPU 0x400000 /* CPU */
#define ROUTAB_ROUTE_ENCRY 0x500800 /* Encryption */
#define ROUTAB_ROUTE_RFP 0x800000 /* RFP */
#define ROUTAB_TYPE_MANAG 0x0 /* Management */
#define ROUTAB_TYPE_CTL 0x1 /* Control */
#define ROUTAB_TYPE_DATA 0x2 /* Data */
#define ROUTAB_SUBTYPE_DATA 0x0
#define ROUTAB_SUBTYPE_DATAACK 0x1
#define ROUTAB_SUBTYPE_DATAPOLL 0x2
#define ROUTAB_SUBTYPE_DATAPOLLACK 0x3
#define ROUTAB_SUBTYPE_NULL 0x4 /* NULL */
#define ROUTAB_SUBTYPE_NULLACK 0x5
#define ROUTAB_SUBTYPE_NULLPOLL 0x6
#define ROUTAB_SUBTYPE_NULLPOLLACK 0x7
#define ROUTAB_SUBTYPE_QOSDATA 0x8 /* QOS DATA */
#define ROUTAB_SUBTYPE_QOSDATAACK 0x9
#define ROUTAB_SUBTYPE_QOSDATAPOLL 0xa
#define ROUTAB_SUBTYPE_QOSDATAACKPOLL 0xb
#define ROUTAB_SUBTYPE_QOSNULL 0xc
#define ROUTAB_SUBTYPE_QOSNULLACK 0xd
#define ROUTAB_SUBTYPE_QOSNULLPOLL 0xe
#define ROUTAB_SUBTYPE_QOSNULLPOLLACK 0xf
#define AGNX_RXM_DELAY11 0x2024 /* delay 11(AB) */
#define AGNX_RXM_SOF_CNT 0x2028 /* SOF Count */
#define AGNX_RXM_FRAG_CNT 0x202c /* Fragment Count*/
#define AGNX_RXM_FCS_CNT 0x2030 /* FCS Count */
#define AGNX_RXM_BSSID_MISS_CNT 0x2034 /* BSSID Miss Count */
#define AGNX_RXM_PDU_ERR_CNT 0x2038 /* PDU Error Count */
#define AGNX_RXM_DEST_MISS_CNT 0x203C /* Destination Miss Count */
#define AGNX_RXM_DROP_CNT 0x2040 /* Drop Count */
#define AGNX_RXM_ABORT_CNT 0x2044 /* Abort Count */
#define AGNX_RXM_RELAY_CNT 0x2048 /* Relay Count */
#define AGNX_RXM_HASH_MISS_CNT 0x204c /* Hash Miss Count */
#define AGNX_RXM_SA_HI 0x2050 /* Address of received packet Hi */
#define AGNX_RXM_SA_LO 0x2054 /* Address of received packet Lo */
#define AGNX_RXM_HASH_DUMP_LST 0x2100 /* Contains Hash Data */
#define AGNX_RXM_HASH_DUMP_MST 0x2104 /* Contains Hash Data */
#define AGNX_RXM_HASH_DUMP_DATA 0x2108 /* The Station ID to dump */
/* Encryption Managment */
#define AGNX_ENCRY_BASE 0x2400
#define AGNX_ENCRY_WEPKEY0 0x2440 /* wep key #0 */
#define AGNX_ENCRY_WEPKEY1 0x2444 /* wep key #1 */
#define AGNX_ENCRY_WEPKEY2 0x2448 /* wep key #2 */
#define AGNX_ENCRY_WEPKEY3 0x244c /* wep key #3 */
#define AGNX_ENCRY_CCMRECTL 0x2460 /* ccm replay control */
/* Band Management Registers */
#define AGNX_BM_BASE 0x2c00
#define AGNX_BM_BMCTL 0x2c00 /* band management control */
#define AGNX_BM_TXWADDR 0x2c18 /* tx workqueue address start */
#define AGNX_BM_TXTOPEER 0x2c24 /* transmit to peers */
#define AGNX_BM_FPLHP 0x2c2c /* free pool list head pointer */
#define AGNX_BM_FPLTP 0x2c30 /* free pool list tail pointer */
#define AGNX_BM_FPCNT 0x2c34 /* free pool count */
#define AGNX_BM_CIPDUWCNT 0x2c38 /* card interface pdu workqueue count */
#define AGNX_BM_SPPDUWCNT 0x2c3c /* sp pdu workqueue count */
#define AGNX_BM_RFPPDUWCNT 0x2c40 /* rfp pdu workqueue count */
#define AGNX_BM_RHPPDUWCNT 0x2c44 /* rhp pdu workqueue count */
#define AGNX_BM_CIWQCTL 0x2c48 /* Card Interface WorkQueue Control */
#define AGNX_BM_CPUTXWCTL 0x2c50 /* cpu tx workqueue control */
#define AGNX_BM_CPURXWCTL 0x2c58 /* cpu rx workqueue control */
#define AGNX_BM_CPULWCTL 0x2c60 /* cpu low workqueue control */
#define AGNX_BM_CPUHWCTL 0x2c68 /* cpu high workqueue control */
#define AGNX_BM_SPTXWCTL 0x2c70 /* sp tx workqueue control */
#define AGNX_BM_SPRXWCTL 0x2c78 /* sp rx workqueue control */
#define AGNX_BM_RFPWCTL 0x2c80 /* RFP workqueue control */
#define AGNX_BM_MTSM 0x2c90 /* Multicast Transmit Station Mask */
/* Card Interface Registers (32bits) */
#define AGNX_CIR_BASE 0x3000
#define AGNX_CIR_BLKCTL 0x3000 /* block control*/
#define AGNX_STAT_TX 0x1
#define AGNX_STAT_RX 0x2
#define AGNX_STAT_X 0x4
/* Below two interrupt flags will be set by our but not CPU or the card */
#define AGNX_STAT_TXD 0x10
#define AGNX_STAT_TXM 0x20
#define AGNX_CIR_ADDRWIN 0x3004 /* Addressable Windows*/
#define AGNX_CIR_ENDIAN 0x3008 /* card endianness */
#define AGNX_CIR_SERIALITF 0x3020 /* serial interface */
#define AGNX_CIR_RXCFG 0x3040 /* receive config */
#define ENABLE_RX_INTERRUPT 0x20
#define RX_CACHE_LINE 0x8
/* the RX fragment length */
#define FRAG_LEN_256 0x0 /* 256B */
#define FRAG_LEN_512 0x1
#define FRAG_LEN_1024 0x2
#define FRAG_LEN_2048 0x3
#define FRAG_BE 0x10
#define AGNX_CIR_RXCTL 0x3050 /* receive control */
/* memory address, chipside */
#define AGNX_CIR_RXCMSTART 0x3054 /* receive client memory start */
#define AGNX_CIR_RXCMEND 0x3058 /* receive client memory end */
/* memory address, pci */
#define AGNX_CIR_RXHOSTADDR 0x3060 /* receive hostside address */
/* memory address, chipside */
#define AGNX_CIR_RXCLIADDR 0x3064 /* receive clientside address */
#define AGNX_CIR_RXDMACTL 0x3068 /* receive dma control */
#define AGNX_CIR_TXCFG 0x3080 /* transmit config */
#define AGNX_CIR_TXMCTL 0x3090 /* Transmit Management Control */
#define ENABLE_TX_INTERRUPT 0x20
#define TX_CACHE_LINE 0x8
#define AGNX_CIR_TXMSTART 0x3094 /* Transmit Management Start */
#define AGNX_CIR_TXMEND 0x3098 /* Transmit Management End */
#define AGNX_CIR_TXDCTL 0x30a0 /* transmit data control */
/* memeory address, chipset */
#define AGNX_CIR_TXDSTART 0x30a4 /* transmit data start */
#define AGNX_CIR_TXDEND 0x30a8 /* transmit data end */
#define AGNX_CIR_TXMHADDR 0x30b0 /* Transmit Management Hostside Address */
#define AGNX_CIR_TXMCADDR 0x30b4 /* Transmit Management Clientside Address */
#define AGNX_CIR_TXDMACTL 0x30b8 /* transmit dma control */
/* Power Managment Unit */
#define AGNX_PM_BASE 0x3c00
#define AGNX_PM_PMCTL 0x3c00 /* PM Control*/
#define AGNX_PM_MACMSW 0x3c08 /* MAC Manual Slow Work Enable */
#define AGNX_PM_RFCTL 0x3c0c /* RF Control */
#define AGNX_PM_PHYMW 0x3c14 /* Phy Mannal Work */
#define AGNX_PM_SOFTRST 0x3c18 /* PMU Soft Reset */
#define AGNX_PM_PLLCTL 0x3c1c /* PMU PLL control*/
#define AGNX_PM_TESTPHY 0x3c24 /* PMU Test Phy */
/* Interrupt Control interface */
#define AGNX_INT_BASE 0x4000
#define AGNX_INT_STAT 0x4000 /* interrupt status */
#define AGNX_INT_MASK 0x400c /* interrupt mask */
/* FIXME */
#define IRQ_TX_BEACON 0x1 /* TX Beacon */
#define IRQ_TX_RETRY 0x8 /* TX Retry Interrupt */
#define IRQ_TX_ACTIVITY 0x10 /* TX Activity */
#define IRQ_RX_ACTIVITY 0x20 /* RX Activity */
/* FIXME I guess that instead RX a none exist staion's packet or
the station hasn't been init */
#define IRQ_RX_X 0x40
#define IRQ_RX_Y 0x80 /* RX ? */
#define IRQ_RX_HASHHIT 0x100 /* RX Hash Hit */
#define IRQ_RX_FRAME 0x200 /* RX Frame */
#define IRQ_ERR_INT 0x400 /* Error Interrupt */
#define IRQ_TX_QUE_FULL 0x800 /* TX Workqueue Full */
#define IRQ_BANDMAN_ERR 0x10000 /* Bandwidth Management Error */
#define IRQ_TX_DISABLE 0x20000 /* TX Disable */
#define IRQ_RX_IVASESKEY 0x80000 /* RX Invalid Session Key */
#define IRQ_RX_KEYIDMIS 0x100000 /* RX key ID Mismatch */
#define IRQ_REP_THHIT 0x200000 /* Replay Threshold Hit */
#define IRQ_TIMER1 0x4000000 /* Timer1 */
#define IRQ_TIMER_CNT 0x10000000 /* Timer Count */
#define IRQ_PHY_FASTINT 0x20000000 /* Phy Fast Interrupt */
#define IRQ_PHY_SLOWINT 0x40000000 /* Phy Slow Interrupt */
#define IRQ_OTHER 0x80000000 /* Unknow interrupt */
#define AGNX_IRQ_ALL 0xffffffff
/* System Interface */
#define AGNX_SYSITF_BASE 0x4400
#define AGNX_SYSITF_SYSMODE 0x4400 /* system mode */
#define AGNX_SYSITF_GPIOIN 0x4410 /* GPIO In */
/* PIN lines for leds? */
#define AGNX_SYSITF_GPIOUT 0x4414 /* GPIO Out */
/* Timer Control */
#define AGNX_TIMCTL_TIMER1 0x4800 /* Timer 1 */
#define AGNX_TIMCTL_TIM1CTL 0x4808 /* Timer 1 Control */
/* Antenna Calibration Interface */
#define AGNX_ACI_BASE 0x5000
#define AGNX_ACI_MODE 0x5000 /* Mode */
#define AGNX_ACI_MEASURE 0x5004 /* Measure */
#define AGNX_ACI_SELCHAIN 0x5008 /* Select Chain */
#define AGNX_ACI_LEN 0x500c /* Length */
#define AGNX_ACI_TIMER1 0x5018 /* Timer 1 */
#define AGNX_ACI_TIMER2 0x501c /* Timer 2 */
#define AGNX_ACI_OFFSET 0x5020 /* Offset */
#define AGNX_ACI_STATUS 0x5030 /* Status */
#define CALI_IDLE 0x0
#define CALI_DONE 0x1
#define CALI_BUSY 0x2
#define CALI_ERR 0x3
#define AGNX_ACI_AICCHA0OVE 0x5034 /* AIC Channel 0 Override */
#define AGNX_ACI_AICCHA1OVE 0x5038 /* AIC Channel 1 Override */
/* Gain Control Registers */
#define AGNX_GCR_BASE 0x9000
/* threshold of primary antenna */
#define AGNX_GCR_THD0A 0x9000 /* threshold? D0 A */
/* low threshold of primary antenna */
#define AGNX_GCR_THD0AL 0x9004 /* threshold? D0 A low */
/* threshold of secondary antenna */
#define AGNX_GCR_THD0B 0x9008 /* threshold? D0_B */
#define AGNX_GCR_DUNSAT 0x900c /* d unsaturated */
#define AGNX_GCR_DSAT 0x9010 /* d saturated */
#define AGNX_GCR_DFIRCAL 0x9014 /* D Fir/Cal */
#define AGNX_GCR_DGCTL11A 0x9018 /* d gain control 11a */
#define AGNX_GCR_DGCTL11B 0x901c /* d gain control 11b */
/* strength of gain */
#define AGNX_GCR_GAININIT 0x9020 /* gain initialization */
#define AGNX_GCR_THNOSIG 0x9024 /* threhold no signal */
#define AGNX_GCR_COARSTEP 0x9028 /* coarse stepping */
#define AGNX_GCR_SIFST11A 0x902c /* sifx time 11a */
#define AGNX_GCR_SIFST11B 0x9030 /* sifx time 11b */
#define AGNX_GCR_CWDETEC 0x9034 /* cw detection */
#define AGNX_GCR_0X38 0x9038 /* ???? */
#define AGNX_GCR_BOACT 0x903c /* BO Active */
#define AGNX_GCR_BOINACT 0x9040 /* BO Inactive */
#define AGNX_GCR_BODYNA 0x9044 /* BO dynamic */
/* 802.11 mode(a,b,g) */
#define AGNX_GCR_DISCOVMOD 0x9048 /* discovery mode */
#define AGNX_GCR_NLISTANT 0x904c /* number of listening antenna */
#define AGNX_GCR_NACTIANT 0x9050 /* number of active antenna */
#define AGNX_GCR_NMEASANT 0x9054 /* number of measuring antenna */
#define AGNX_GCR_NCAPTANT 0x9058 /* number of capture antenna */
#define AGNX_GCR_THCAP11A 0x905c /* threshold capture 11a */
#define AGNX_GCR_THCAP11B 0x9060 /* threshold capture 11b */
#define AGNX_GCR_THCAPRX11A 0x9064 /* threshold capture rx 11a */
#define AGNX_GCR_THCAPRX11B 0x9068 /* threshold capture rx 11b */
#define AGNX_GCR_THLEVDRO 0x906c /* threshold level drop */
#define AGNX_GCR_GAINSET0 0x9070 /* Gainset 0 */
#define AGNX_GCR_GAINSET1 0x9074 /* Gainset 1 */
#define AGNX_GCR_GAINSET2 0x9078 /* Gainset 2 */
#define AGNX_GCR_MAXRXTIME11A 0x907c /* maximum rx time 11a */
#define AGNX_GCR_MAXRXTIME11B 0x9080 /* maximum rx time 11b */
#define AGNX_GCR_CORRTIME 0x9084 /* correction time */
/* reset the subsystem, 0 = disable, 1 = enable */
#define AGNX_GCR_RSTGCTL 0x9088 /* reset gain control */
/* channel receiving */
#define AGNX_GCR_RXCHANEL 0x908c /* receive channel */
#define AGNX_GCR_NOISE0 0x9090 /* Noise 0 */
#define AGNX_GCR_NOISE1 0x9094 /* Noise 1 */
#define AGNX_GCR_NOISE2 0x9098 /* Noise 2 */
#define AGNX_GCR_SIGHTH 0x909c /* Signal High Threshold */
#define AGNX_GCR_SIGLTH 0x90a0 /* Signal Low Threshold */
#define AGNX_GCR_CORRDROP 0x90a4 /* correction drop */
/* threshold of tertiay antenna */
#define AGNX_GCR_THCD 0x90a8 /* threshold? CD */
#define AGNX_GCR_THCS 0x90ac /* threshold? CS */
#define AGNX_GCR_MAXPOWDIFF 0x90b8 /* maximum power difference */
#define AGNX_GCR_TRACNT4 0x90ec /* Transition Count 4 */
#define AGNX_GCR_TRACNT5 0x90f0 /* transition count 5 */
#define AGNX_GCR_TRACNT6 0x90f4 /* transition count 6 */
#define AGNX_GCR_TRACNT7 0x90f8 /* transition coutn 7 */
#define AGNX_GCR_TESTBUS 0x911c /* test bus */
#define AGNX_GCR_CHAINNUM 0x9120 /* Number of Chains */
#define AGNX_GCR_ANTCFG 0x9124 /* Antenna Config */
#define AGNX_GCR_THJUMP 0x912c /* threhold jump */
#define AGNX_GCR_THPOWER 0x9130 /* threshold power */
#define AGNX_GCR_THPOWCLIP 0x9134 /* threshold power clip*/
#define AGNX_GCR_FORCECTLCLK 0x9138 /* Force Gain Control Clock */
#define AGNX_GCR_GAINSETWRITE 0x913c /* Gainset Write */
#define AGNX_GCR_THD0BTFEST 0x9140 /* threshold d0 b tf estimate */
#define AGNX_GCR_THRX11BPOWMIN 0x9144 /* threshold rx 11b power minimum */
#define AGNX_GCR_0X14c 0x914c /* ?? */
#define AGNX_GCR_0X150 0x9150 /* ?? */
#define AGNX_GCR_RXOVERIDE 0x9194 /* recieve override */
#define AGNX_GCR_WATCHDOG 0x91b0 /* watchdog timeout */
/* Spi Interface */
#define AGNX_SPI_BASE 0xdc00
#define AGNX_SPI_CFG 0xdc00 /* spi configuration */
/* Only accept 16 bits */
#define AGNX_SPI_WMSW 0xdc04 /* write most significant word */
/* Only accept 16 bits */
#define AGNX_SPI_WLSW 0xdc08 /* write least significant word */
#define AGNX_SPI_CTL 0xdc0c /* spi control */
#define AGNX_SPI_RMSW 0xdc10 /* read most significant word */
#define AGNX_SPI_RLSW 0xdc14 /* read least significant word */
/* SPI Control Mask */
#define SPI_READ_CTL 0x4000 /* read control */
#define SPI_BUSY_CTL 0x8000 /* busy control */
/* RF and synth chips in spi */
#define RF_CHIP0 0x400
#define RF_CHIP1 0x800
#define RF_CHIP2 0x1000
#define SYNTH_CHIP 0x2000
/* Unknown register */
#define AGNX_UNKNOWN_BASE 0x7800
/* FIXME MonitorGain */
#define AGNX_MONGCR_BASE 0x12000
/* Gain Table */
#define AGNX_GAIN_TABLE 0x12400
/* The initial FIR coefficient table */
#define AGNX_FIR_BASE 0x19804
#define AGNX_ENGINE_LOOKUP_TBL 0x800
/* eeprom commands */
#define EEPROM_CMD_NULL 0x0 /* NULL */
#define EEPROM_CMD_WRITE 0x2 /* write */
#define EEPROM_CMD_READ 0x3 /* read */
#define EEPROM_CMD_STATUSREAD 0x5 /* status register read */
#define EEPROM_CMD_WRITEENABLE 0x6 /* write enable */
#define EEPROM_CMD_CONFIGURE 0x7 /* configure */
#define EEPROM_DATAFORCOFIGURE 0x6 /* ??? */
/* eeprom address */
#define EEPROM_ADDR_SUBVID 0x0 /* Sub Vendor ID */
#define EEPROM_ADDR_SUBSID 0x2 /* Sub System ID */
#define EEPROM_ADDR_MACADDR 0x146 /* MAC Address */
#define EEPROM_ADDR_LOTYPE 0x14f /* LO type */
struct agnx_eeprom {
u8 data; /* date */
u16 address; /* address in EEPROM */
u8 cmd; /* command, unknown, status */
} __attribute__((__packed__));
#define AGNX_EEPROM_COMMAND_SHIFT 5
#define AGNX_EEPROM_COMMAND_STAT 0x01
void disable_receiver(struct agnx_priv *priv);
void enable_receiver(struct agnx_priv *priv);
u8 read_from_eeprom(struct agnx_priv *priv, u16 address);
void agnx_hw_init(struct agnx_priv *priv);
int agnx_hw_reset(struct agnx_priv *priv);
int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len);
void agnx_set_bssid(struct agnx_priv *priv, u8 *bssid);
void enable_power_saving(struct agnx_priv *priv);
void disable_power_saving(struct agnx_priv *priv);
void calibrate_antenna_period(unsigned long data);
#endif /* AGNX_PHY_H_ */

894
drivers/staging/agnx/rf.c Normal file
View File

@ -0,0 +1,894 @@
/**
* Airgo MIMO wireless driver
*
* Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
* Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
* works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "phy.h"
#include "table.h"
/* FIXME! */
static inline void spi_write(void __iomem *region, u32 chip_ids, u32 sw,
u16 size, u32 control)
{
u32 reg;
u32 lsw = sw & 0xffff; /* lower 16 bits of sw*/
u32 msw = sw >> 16; /* high 16 bits of sw */
/* FIXME Write Most Significant Word of the 32bit data to MSW */
/* FIXME And Least Significant Word to LSW */
iowrite32((lsw), region + AGNX_SPI_WLSW);
iowrite32((msw), region + AGNX_SPI_WMSW);
reg = chip_ids | size | control;
/* Write chip id(s), write size and busy control to Control Register */
iowrite32((reg), region + AGNX_SPI_CTL);
/* Wait for Busy control to clear */
spi_delay();
}
/*
* Write to SPI Synth register
*/
static inline void spi_sy_write(void __iomem *region, u32 chip_ids, u32 sw)
{
/* FIXME the size 0x15 is a magic value*/
spi_write(region, chip_ids, sw, 0x15, SPI_BUSY_CTL);
}
/*
* Write to SPI RF register
*/
static inline void spi_rf_write(void __iomem *region, u32 chip_ids, u32 sw)
{
/* FIXME the size 0xd is a magic value*/
spi_write(region, chip_ids, sw, 0xd, SPI_BUSY_CTL);
} /* spi_rf_write */
/*
* Write to SPI with Read Control bit set
*/
inline void spi_rc_write(void __iomem *region, u32 chip_ids, u32 sw)
{
/* FIXME the size 0xe5 is a magic value */
spi_write(region, chip_ids, sw, 0xe5, SPI_BUSY_CTL|SPI_READ_CTL);
}
/* Get the active chains's count */
static int get_active_chains(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int num = 0;
u32 reg;
AGNX_TRACE;
spi_rc_write(ctl, RF_CHIP0, 0x21);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (reg == 1)
num++;
spi_rc_write(ctl, RF_CHIP1, 0x21);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (reg == 1)
num++;
spi_rc_write(ctl, RF_CHIP2, 0x21);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (reg == 1)
num++;
spi_rc_write(ctl, RF_CHIP0, 0x26);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (0x33 != reg)
printk(KERN_WARNING PFX "Unmatched rf chips result\n");
return num;
} /* get_active_chains */
void rf_chips_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
int num;
AGNX_TRACE;
if (priv->revid == 1) {
reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
reg |= 0x8;
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
}
/* Set SPI clock speed to 200NS */
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xF;
reg |= 0x3;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
/* Set SPI clock speed to 50NS */
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xF;
reg |= 0x1;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1101);
num = get_active_chains(priv);
printk(KERN_INFO PFX "Active chains are %d\n", num);
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xF;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1908);
} /* rf_chips_init */
static u32 channel_tbl[15][9] = {
{0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{1, 0x00, 0x00, 0x624, 0x00, 0x1a4, 0x28, 0x00, 0x1e},
{2, 0x00, 0x00, 0x615, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
{3, 0x00, 0x00, 0x61a, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
{4, 0x00, 0x00, 0x61f, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
{5, 0x00, 0x00, 0x624, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
{6, 0x00, 0x00, 0x61f, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
{7, 0x00, 0x00, 0x624, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
{8, 0x00, 0x00, 0x629, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
{9, 0x00, 0x00, 0x624, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
{10, 0x00, 0x00, 0x629, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
{11, 0x00, 0x00, 0x62e, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
{12, 0x00, 0x00, 0x633, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
{13, 0x00, 0x00, 0x628, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
{14, 0x00, 0x00, 0x644, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
};
static inline void
channel_tbl_write(struct agnx_priv *priv, unsigned int channel, unsigned int reg_num)
{
void __iomem *ctl = priv->ctl;
u32 reg;
reg = channel_tbl[channel][reg_num];
reg <<= 4;
reg |= reg_num;
spi_sy_write(ctl, SYNTH_CHIP, reg);
}
static void synth_freq_set(struct agnx_priv *priv, unsigned int channel)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
/* Set the Clock bits to 50NS */
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xF;
reg |= 0x1;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
/* Write 0x00c0 to LSW and 0x3 to MSW of Synth Chip */
spi_sy_write(ctl, SYNTH_CHIP, 0x300c0);
spi_sy_write(ctl, SYNTH_CHIP, 0x32);
/* # Write to Register 1 on the Synth Chip */
channel_tbl_write(priv, channel, 1);
/* # Write to Register 3 on the Synth Chip */
channel_tbl_write(priv, channel, 3);
/* # Write to Register 6 on the Synth Chip */
channel_tbl_write(priv, channel, 6);
/* # Write to Register 5 on the Synth Chip */
channel_tbl_write(priv, channel, 5);
/* # Write to register 8 on the Synth Chip */
channel_tbl_write(priv, channel, 8);
/* FIXME Clear the clock bits */
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xf;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
} /* synth_chip_init */
static void antenna_init(struct agnx_priv *priv, int num_antenna)
{
void __iomem *ctl = priv->ctl;
switch (num_antenna) {
case 1:
agnx_write32(ctl, AGNX_GCR_NLISTANT, 1);
agnx_write32(ctl, AGNX_GCR_NMEASANT, 1);
agnx_write32(ctl, AGNX_GCR_NACTIANT, 1);
agnx_write32(ctl, AGNX_GCR_NCAPTANT, 1);
agnx_write32(ctl, AGNX_GCR_ANTCFG, 7);
agnx_write32(ctl, AGNX_GCR_BOACT, 34);
agnx_write32(ctl, AGNX_GCR_BOINACT, 34);
agnx_write32(ctl, AGNX_GCR_BODYNA, 30);
agnx_write32(ctl, AGNX_GCR_THD0A, 125);
agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
agnx_write32(ctl, AGNX_GCR_THD0B, 90);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 80);
agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
agnx_write32(ctl, AGNX_GCR_SIGLTH, 16);
break;
case 2:
agnx_write32(ctl, AGNX_GCR_NLISTANT, 2);
agnx_write32(ctl, AGNX_GCR_NMEASANT, 2);
agnx_write32(ctl, AGNX_GCR_NACTIANT, 2);
agnx_write32(ctl, AGNX_GCR_NCAPTANT, 2);
agnx_write32(ctl, AGNX_GCR_ANTCFG, 15);
agnx_write32(ctl, AGNX_GCR_BOACT, 36);
agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
agnx_write32(ctl, AGNX_GCR_THD0A, 120);
agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
agnx_write32(ctl, AGNX_GCR_THD0B, 80);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
agnx_write32(ctl, AGNX_GCR_SIGLTH, 32);
break;
case 3:
agnx_write32(ctl, AGNX_GCR_NLISTANT, 3);
agnx_write32(ctl, AGNX_GCR_NMEASANT, 3);
agnx_write32(ctl, AGNX_GCR_NACTIANT, 3);
agnx_write32(ctl, AGNX_GCR_NCAPTANT, 3);
agnx_write32(ctl, AGNX_GCR_ANTCFG, 31);
agnx_write32(ctl, AGNX_GCR_BOACT, 36);
agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
agnx_write32(ctl, AGNX_GCR_THD0A, 100);
agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
agnx_write32(ctl, AGNX_GCR_THD0B, 70);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
agnx_write32(ctl, AGNX_GCR_SIGLTH, 48);
// agnx_write32(ctl, AGNX_GCR_SIGLTH, 16);
break;
default:
printk(KERN_WARNING PFX "Unknow antenna number\n");
}
} /* antenna_init */
static void chain_update(struct agnx_priv *priv, u32 chain)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
spi_rc_write(ctl, RF_CHIP0, 0x20);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (reg == 0x4)
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
else if (reg != 0x0)
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
else {
if (chain == 3 || chain == 6) {
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
} else if (chain == 2 || chain == 4) {
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
spi_rf_write(ctl, RF_CHIP2, 0x1005);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x824);
} else if (chain == 1) {
spi_rf_write(ctl, RF_CHIP0, reg|0x1000);
spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1004);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xc36);
}
}
spi_rc_write(ctl, RF_CHIP0, 0x22);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
switch (reg) {
case 0:
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);
break;
case 1:
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
break;
case 2:
if (chain == 6 || chain == 4) {
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1202);
spi_rf_write(ctl, RF_CHIP2, 0x1005);
} else if (chain < 3) {
spi_rf_write(ctl, RF_CHIP0, 0x1202);
spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1005);
}
break;
default:
if (chain == 3) {
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
spi_rf_write(ctl, RF_CHIP2, 0x1201);
} else if (chain == 2) {
spi_rf_write(ctl, RF_CHIP0, 0x1203);
spi_rf_write(ctl, RF_CHIP2, 0x1200);
spi_rf_write(ctl, RF_CHIP1, 0x1201);
} else if (chain == 1) {
spi_rf_write(ctl, RF_CHIP0, 0x1203);
spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1200);
} else if (chain == 4) {
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
spi_rf_write(ctl, RF_CHIP2, 0x1201);
} else {
spi_rf_write(ctl, RF_CHIP0, 0x1203);
spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1201);
}
}
} /* chain_update */
static void antenna_config(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
/* Write 0x0 to the TX Management Control Register Enable bit */
reg = agnx_read32(ctl, AGNX_TXM_CTL);
reg &= ~0x1;
agnx_write32(ctl, AGNX_TXM_CTL, reg);
/* FIXME */
/* Set initial value based on number of Antennae */
antenna_init(priv, 3);
/* FIXME Update Power Templates for current valid Stations */
/* sta_power_init(priv, 0);*/
/* FIXME the number of chains should get from eeprom*/
chain_update(priv, AGNX_CHAINS_MAX);
} /* antenna_config */
void calibrate_oscillator(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
reg |= 0x10;
agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 1);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 1);
agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
/* (Residual DC Calibration) to Calibration Mode */
agnx_write32(ctl, AGNX_ACI_MODE, 0x2);
spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1004);
agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
/* (TX LO Calibration) to Calibration Mode */
agnx_write32(ctl, AGNX_ACI_MODE, 0x4);
do {
u32 reg1, reg2, reg3;
/* Enable Power Saving Control */
enable_power_saving(priv);
/* Save the following registers to restore */
reg1 = ioread32(ctl + 0x11000);
reg2 = ioread32(ctl + 0xec50);
reg3 = ioread32(ctl + 0xec54);
wmb();
agnx_write32(ctl, 0x11000, 0xcfdf);
agnx_write32(ctl, 0xec50, 0x70);
/* Restore the registers */
agnx_write32(ctl, 0x11000, reg1);
agnx_write32(ctl, 0xec50, reg2);
agnx_write32(ctl, 0xec54, reg3);
/* Disable Power Saving Control */
disable_power_saving(priv);
} while (0);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0);
} /* calibrate_oscillator */
static void radio_channel_set(struct agnx_priv *priv, unsigned int channel)
{
void __iomem *ctl = priv->ctl;
unsigned int freq = priv->band.channels[channel - 1].center_freq;
u32 reg;
AGNX_TRACE;
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
/* Set SPI Clock to 50 Ns */
reg = agnx_read32(ctl, AGNX_SPI_CFG);
reg &= ~0xF;
reg |= 0x1;
agnx_write32(ctl, AGNX_SPI_CFG, reg);
/* Clear the Disable Tx interrupt bit in Interrupt Mask */
/* reg = agnx_read32(ctl, AGNX_INT_MASK); */
/* reg &= ~IRQ_TX_DISABLE; */
/* agnx_write32(ctl, AGNX_INT_MASK, reg); */
/* Band Selection */
reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
reg |= 0x8;
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
/* FIXME Set the SiLabs Chip Frequency */
synth_freq_set(priv, channel);
reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
reg |= 0x80100030;
agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
reg |= 0x20009;
agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1100);
/* Load the MonitorGain Table */
monitor_gain_table_init(priv);
/* Load the TX Fir table */
tx_fir_table_init(priv);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg |= 0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x22);
udelay(80);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
reg = agnx_read32(ctl, 0xec50);
reg |= 0x4f;
agnx_write32(ctl, 0xec50, reg);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
agnx_write32(ctl, 0x11008, 0x1);
agnx_write32(ctl, 0x1100c, 0x0);
agnx_write32(ctl, 0x11008, 0x0);
agnx_write32(ctl, 0xec50, 0xc);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
agnx_write32(ctl, 0x11010, 0x6e);
agnx_write32(ctl, 0x11014, 0x6c);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
/* Calibrate the Antenna */
/* antenna_calibrate(priv); */
/* Calibrate the TxLocalOscillator */
calibrate_oscillator(priv);
reg = agnx_read32(ctl, AGNX_PM_PMCTL);
reg &= ~0x8;
agnx_write32(ctl, AGNX_PM_PMCTL, reg);
agnx_write32(ctl, AGNX_GCR_GAININIT, 0xa);
agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
agnx_write32(ctl, 0x11018, 0xb);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0);
/* Write Frequency to Gain Control Channel */
agnx_write32(ctl, AGNX_GCR_RXCHANEL, freq);
/* Write 0x140000/Freq to 0x9c08 */
reg = 0x140000/freq;
agnx_write32(ctl, 0x9c08, reg);
reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
reg &= ~0x80100030;
agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
reg &= ~0x20009;
reg |= 0x1;
agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
agnx_write32(ctl, AGNX_ACI_MODE, 0x0);
/* FIXME According to Number of Chains: */
/* 1. 1: */
/* 1. Write 0x1203 to RF Chip 0 */
/* 2. Write 0x1200 to RF Chips 1 +2 */
/* 2. 2: */
/* 1. Write 0x1203 to RF Chip 0 */
/* 2. Write 0x1200 to RF Chip 2 */
/* 3. Write 0x1201 to RF Chip 1 */
/* 3. 3: */
/* 1. Write 0x1203 to RF Chip 0 */
/* 2. Write 0x1201 to RF Chip 1 + 2 */
/* 4. 4: */
/* 1. Write 0x1203 to RF Chip 0 + 1 */
/* 2. Write 0x1200 to RF Chip 2 */
/* 5. 6: */
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
spi_rf_write(ctl, RF_CHIP2, 0x1201);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
/* FIXME Set the Disable Tx interrupt bit in Interrupt Mask
(Or 0x20000 to Interrupt Mask) */
/* reg = agnx_read32(ctl, AGNX_INT_MASK); */
/* reg |= IRQ_TX_DISABLE; */
/* agnx_write32(ctl, AGNX_INT_MASK, reg); */
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
/* Configure the Antenna */
antenna_config(priv);
/* Write 0x0 to Discovery Mode Enable detect G, B, A packet? */
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0);
reg = agnx_read32(ctl, AGNX_RXM_REQRATE);
reg |= 0x80000000;
agnx_write32(ctl, AGNX_RXM_REQRATE, reg);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
/* enable radio on and the power LED */
reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
reg &= ~0x1;
reg |= 0x2;
agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
reg = agnx_read32(ctl, AGNX_TXM_CTL);
reg |= 0x1;
agnx_write32(ctl, AGNX_TXM_CTL, reg);
} /* radio_channel_set */
static void base_band_filter_calibrate(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1001);
agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x0);
spi_rc_write(ctl, RF_CHIP0, 0x27);
spi_rc_write(ctl, RF_CHIP1, 0x27);
spi_rc_write(ctl, RF_CHIP2, 0x27);
agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x1);
}
static void print_offset(struct agnx_priv *priv, u32 chain)
{
void __iomem *ctl = priv->ctl;
u32 offset;
iowrite32((chain), ctl + AGNX_ACI_SELCHAIN);
udelay(10);
offset = (ioread32(ctl + AGNX_ACI_OFFSET));
printk(PFX "Chain is 0x%x, Offset is 0x%x\n", chain, offset);
}
void print_offsets(struct agnx_priv *priv)
{
print_offset(priv, 0);
print_offset(priv, 4);
print_offset(priv, 1);
print_offset(priv, 5);
print_offset(priv, 2);
print_offset(priv, 6);
}
struct chains {
u32 cali; /* calibrate value*/
#define NEED_CALIBRATE 0
#define SUCCESS_CALIBRATE 1
int status;
};
static void chain_calibrate(struct agnx_priv *priv, struct chains *chains,
unsigned int num)
{
void __iomem *ctl = priv->ctl;
u32 calibra = chains[num].cali;
if (num < 3)
calibra |= 0x1400;
else
calibra |= 0x1500;
switch (num) {
case 0:
case 4:
spi_rf_write(ctl, RF_CHIP0, calibra);
break;
case 1:
case 5:
spi_rf_write(ctl, RF_CHIP1, calibra);
break;
case 2:
case 6:
spi_rf_write(ctl, RF_CHIP2, calibra);
break;
default:
BUG();
}
} /* chain_calibrate */
static void inline get_calibrete_value(struct agnx_priv *priv, struct chains *chains,
unsigned int num)
{
void __iomem *ctl = priv->ctl;
u32 offset;
iowrite32((num), ctl + AGNX_ACI_SELCHAIN);
/* FIXME */
udelay(10);
offset = (ioread32(ctl + AGNX_ACI_OFFSET));
if (offset < 0xf) {
chains[num].status = SUCCESS_CALIBRATE;
return;
}
if (num == 0 || num == 1 || num == 2) {
if ( 0 == chains[num].cali)
chains[num].cali = 0xff;
else
chains[num].cali--;
} else
chains[num].cali++;
chains[num].status = NEED_CALIBRATE;
}
static inline void calibra_delay(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
unsigned int i = 100;
wmb();
while (i--) {
reg = (ioread32(ctl + AGNX_ACI_STATUS));
if (reg == 0x4000)
break;
udelay(10);
}
if (!i)
printk(PFX "calibration failed\n");
}
void do_calibration(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
struct chains chains[7];
unsigned int i, j;
AGNX_TRACE;
for (i = 0; i < 7; i++) {
if (i == 3)
continue;
chains[i].cali = 0x7f;
chains[i].status = NEED_CALIBRATE;
}
/* FIXME 0x300 is a magic number */
for (j = 0; j < 0x300; j++) {
if (chains[0].status == SUCCESS_CALIBRATE &&
chains[1].status == SUCCESS_CALIBRATE &&
chains[2].status == SUCCESS_CALIBRATE &&
chains[4].status == SUCCESS_CALIBRATE &&
chains[5].status == SUCCESS_CALIBRATE &&
chains[6].status == SUCCESS_CALIBRATE)
break;
/* Attention, there is no chain 3 */
for (i = 0; i < 7; i++) {
if (i == 3)
continue;
if (chains[i].status == NEED_CALIBRATE)
chain_calibrate(priv, chains, i);
}
/* Write 0x1 to Calibration Measure */
iowrite32((0x1), ctl + AGNX_ACI_MEASURE);
calibra_delay(priv);
for (i = 0; i < 7; i++) {
if (i == 3)
continue;
get_calibrete_value(priv, chains, i);
}
}
printk(PFX "Clibrate times is %d\n", j);
print_offsets(priv);
} /* do_calibration */
void antenna_calibrate(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
AGNX_TRACE;
agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3);
agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3);
agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f);
agnx_write32(ctl, AGNX_GCR_BOACT, 0x24);
agnx_write32(ctl, AGNX_GCR_BOINACT, 0x24);
agnx_write32(ctl, AGNX_GCR_BODYNA, 0x20);
agnx_write32(ctl, AGNX_GCR_THD0A, 0x64);
agnx_write32(ctl, AGNX_GCR_THD0AL, 0x64);
agnx_write32(ctl, AGNX_GCR_THD0B, 0x46);
agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c);
agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x64);
agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x30);
spi_rc_write(ctl, RF_CHIP0, 0x20);
/* Fixme */
udelay(80);
/* 1. Should read 0x0 */
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (0x0 != reg)
printk(KERN_WARNING PFX "Unmatched rf chips result\n");
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
spi_rc_write(ctl, RF_CHIP0, 0x22);
udelay(80);
reg = agnx_read32(ctl, AGNX_SPI_RLSW);
if (0x0 != reg)
printk(KERN_WARNING PFX "Unmatched rf chips result\n");
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
reg |= 0x1c000032;
agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
reg |= 0x0003f07;
agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
reg = agnx_read32(ctl, 0xec50);
reg |= 0x40;
agnx_write32(ctl, 0xec50, reg);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff8);
agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
agnx_write32(ctl, AGNX_GCR_CHAINNUM, 0x6);
agnx_write32(ctl, 0x19874, 0x0);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);
/* Calibrate the BaseBandFilter */
base_band_filter_calibrate(priv);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);
agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);
agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);
/* Measure Calibration */
agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
calibra_delay(priv);
/* do calibration */
do_calibration(priv);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);
agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);
disable_receiver(priv);
} /* antenna_calibrate */
void __antenna_calibrate(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
/* Calibrate the BaseBandFilter */
/* base_band_filter_calibrate(priv); */
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);
agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);
agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);
agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);
/* Measure Calibration */
agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
calibra_delay(priv);
do_calibration(priv);
agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
reg &= 0xf;
agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);
agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);
/* Write 0x3 Gain Control Discovery Mode */
enable_receiver(priv);
}
int agnx_set_channel(struct agnx_priv *priv, unsigned int channel)
{
AGNX_TRACE;
printk(KERN_ERR PFX "Channel is %d %s\n", channel, __func__);
radio_channel_set(priv, channel);
return 0;
}

219
drivers/staging/agnx/sta.c Normal file
View File

@ -0,0 +1,219 @@
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include "phy.h"
#include "sta.h"
#include "debug.h"
void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
{
void __iomem *ctl = priv->ctl;
reglo &= 0xFFFF;
reglo |= 0x30000000;
reglo |= 0x40000000; /* Set status busy */
reglo |= sta_id << 16;
iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
}
void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id)
{
void __iomem *ctl = priv->ctl;
u32 reghi, reglo;
if (!is_valid_ether_addr(mac_addr))
printk(KERN_WARNING PFX "Update hash table: Invalid hwaddr!\n");
reghi = mac_addr[0] << 24 | mac_addr[1] << 16 | mac_addr[2] << 8 | mac_addr[3];
reglo = mac_addr[4] << 8 | mac_addr[5];
reglo |= 0x10000000; /* Set hash commmand */
reglo |= 0x40000000; /* Set status busy */
reglo |= sta_id << 16;
iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
if (!(reglo & 0x80000000))
printk(KERN_WARNING PFX "Update hash table failed\n");
}
void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
{
void __iomem *ctl = priv->ctl;
reglo &= 0xFFFF;
reglo |= 0x20000000;
reglo |= 0x40000000; /* Set status busy */
reglo |= sta_id << 16;
iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
}
void hash_dump(struct agnx_priv *priv, u8 sta_id)
{
void __iomem *ctl = priv->ctl;
u32 reghi, reglo;
reglo = 0x0; /* dump command */
reglo|= 0x40000000; /* status bit */
iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
iowrite32(sta_id << 16, ctl + AGNX_RXM_HASH_DUMP_DATA);
udelay(80);
reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
printk(PFX "hash cmd are : %.8x%.8x\n", reghi, reglo);
reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_FLAG);
printk(PFX "hash flag is : %.8x\n", reghi);
reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_MST);
reglo = ioread32(ctl + AGNX_RXM_HASH_DUMP_LST);
printk(PFX "hash dump mst lst: %.8x%.8x\n", reghi, reglo);
reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_DATA);
printk(PFX "hash dump data: %.8x\n", reghi);
}
void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
{
void __iomem *ctl = priv->ctl;
memcpy_fromio(power, ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
sizeof(*power));
}
inline void
set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
{
void __iomem *ctl = priv->ctl;
/* FIXME 2. Write Template to offset + station number */
memcpy_toio(ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
power, sizeof(*power));
}
void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
unsigned int sta_idx, unsigned int wq_idx)
{
void __iomem *data = priv->data;
memcpy_fromio(tx_wq, data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx +
sizeof(*tx_wq) * wq_idx, sizeof(*tx_wq));
}
inline void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
unsigned int sta_idx, unsigned int wq_idx)
{
void __iomem *data = priv->data;
memcpy_toio(data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx +
sizeof(*tx_wq) * wq_idx, tx_wq, sizeof(*tx_wq));
}
void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx)
{
void __iomem *data = priv->data;
memcpy_fromio(sta, data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
sizeof(*sta));
}
inline void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx)
{
void __iomem *data = priv->data;
memcpy_toio(data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
sta, sizeof(*sta));
}
/* FIXME */
void sta_power_init(struct agnx_priv *priv, unsigned int sta_idx)
{
struct agnx_sta_power power;
u32 reg;
AGNX_TRACE;
memset(&power, 0, sizeof(power));
reg = agnx_set_bits(EDCF, EDCF_SHIFT, 0x1);
power.reg = cpu_to_le32(reg);
set_sta_power(priv, &power, sta_idx);
udelay(40);
} /* add_power_template */
/* @num: The #number of station that is visible to the card */
static void sta_tx_workqueue_init(struct agnx_priv *priv, unsigned int sta_idx)
{
struct agnx_sta_tx_wq tx_wq;
u32 reg;
unsigned int i;
memset(&tx_wq, 0, sizeof(tx_wq));
reg = agnx_set_bits(WORK_QUEUE_VALID, WORK_QUEUE_VALID_SHIFT, 1);
reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 1);
// reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 0);
tx_wq.reg2 |= cpu_to_le32(reg);
/* Suppose all 8 traffic class are used */
for (i = 0; i < STA_TX_WQ_NUM; i++)
set_sta_tx_wq(priv, &tx_wq, sta_idx, i);
} /* sta_tx_workqueue_init */
static void sta_traffic_init(struct agnx_sta_traffic *traffic)
{
u32 reg;
memset(traffic, 0, sizeof(*traffic));
reg = agnx_set_bits(NEW_PACKET, NEW_PACKET_SHIFT, 1);
reg |= agnx_set_bits(TRAFFIC_VALID, TRAFFIC_VALID_SHIFT, 1);
// reg |= agnx_set_bits(TRAFFIC_ACK_TYPE, TRAFFIC_ACK_TYPE_SHIFT, 1);
traffic->reg0 = cpu_to_le32(reg);
/* 3. setting RX Sequence Number to 4095 */
reg = agnx_set_bits(RX_SEQUENCE_NUM, RX_SEQUENCE_NUM_SHIFT, 4095);
traffic->reg1 = cpu_to_le32(reg);
}
/* @num: The #number of station that is visible to the card */
void sta_init(struct agnx_priv *priv, unsigned int sta_idx)
{
/* FIXME the length of sta is 256 bytes Is that
* dangerous to stack overflow? */
struct agnx_sta sta;
u32 reg;
int i;
memset(&sta, 0, sizeof(sta));
/* Set valid to 1 */
reg = agnx_set_bits(STATION_VALID, STATION_VALID_SHIFT, 1);
/* Set Enable Concatenation to 0 (?) */
reg |= agnx_set_bits(ENABLE_CONCATENATION, ENABLE_CONCATENATION_SHIFT, 0);
/* Set Enable Decompression to 0 (?) */
reg |= agnx_set_bits(ENABLE_DECOMPRESSION, ENABLE_DECOMPRESSION_SHIFT, 0);
sta.reg = cpu_to_le32(reg);
/* Initialize each of the Traffic Class Structures by: */
for (i = 0; i < 8; i++)
sta_traffic_init(sta.traffic + i);
set_sta(priv, &sta, sta_idx);
sta_tx_workqueue_init(priv, sta_idx);
} /* sta_descriptor_init */

222
drivers/staging/agnx/sta.h Normal file
View File

@ -0,0 +1,222 @@
#ifndef AGNX_STA_H_
#define AGNX_STA_H_
#define STA_TX_WQ_NUM 8 /* The number of TX workqueue one STA has */
struct agnx_hash_cmd {
__be32 cmdhi;
#define MACLO 0xFFFF0000
#define MACLO_SHIFT 16
#define STA_ID 0x0000FFF0
#define STA_ID_SHIFT 4
#define CMD 0x0000000C
#define CMD_SHIFT 2
#define STATUS 0x00000002
#define STATUS_SHIFT 1
#define PASS 0x00000001
#define PASS_SHIFT 1
__be32 cmdlo;
}__attribute__((__packed__));
/*
* Station Power Template
* FIXME Just for agn100 yet
*/
struct agnx_sta_power {
__le32 reg;
#define SIGNAL 0x000000FF /* signal */
#define SIGNAL_SHIFT 0
#define RATE 0x00000F00
#define RATE_SHIFT 8
#define TIFS 0x00001000
#define TIFS_SHIFT 12
#define EDCF 0x00002000
#define EDCF_SHIFT 13
#define CHANNEL_BOND 0x00004000
#define CHANNEL_BOND_SHIFT 14
#define PHY_MODE 0x00038000
#define PHY_MODE_SHIFT 15
#define POWER_LEVEL 0x007C0000
#define POWER_LEVEL_SHIFT 18
#define NUM_TRANSMITTERS 0x00800000
#define NUM_TRANSMITTERS_SHIFT 23
} __attribute__((__packed__));
/*
* TX Workqueue Descriptor
*/
struct agnx_sta_tx_wq {
__le32 reg0;
#define HEAD_POINTER_LOW 0xFF000000 /* Head pointer low */
#define HEAD_POINTER_LOW_SHIFT 24
#define TAIL_POINTER 0x00FFFFFF /* Tail pointer */
#define TAIL_POINTER_SHIFT 0
__le32 reg3;
#define ACK_POINTER_LOW 0xFFFF0000 /* ACK pointer low */
#define ACK_POINTER_LOW_SHIFT 16
#define HEAD_POINTER_HIGH 0x0000FFFF /* Head pointer high */
#define HEAD_POINTER_HIGH_SHIFT 0
__le32 reg1;
/* ACK timeout tail packet count */
#define ACK_TIMOUT_TAIL_PACK_CNT 0xFFF00000
#define ACK_TIMOUT_TAIL_PACK_CNT_SHIFT 20
/* Head timeout tail packet count */
#define HEAD_TIMOUT_TAIL_PACK_CNT 0x000FFF00
#define HEAD_TIMOUT_TAIL_PACK_CNT_SHIFT 8
#define ACK_POINTER_HIGH 0x000000FF /* ACK pointer high */
#define ACK_POINTER_HIGH_SHIFT 0
__le32 reg2;
#define WORK_QUEUE_VALID 0x80000000 /* valid */
#define WORK_QUEUE_VALID_SHIFT 31
#define WORK_QUEUE_ACK_TYPE 0x40000000 /* ACK type */
#define WORK_QUEUE_ACK_TYPE_SHIFT 30
/* Head timeout window limit fragmentation count */
#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT 0x3FFF0000
#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT_SHIFT 16
/* Head timeout window limit byte count */
#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT 0x0000FFFF
#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT_SHIFT 0
} __attribute__((__packed__));
/*
* Traffic Class Structure
*/
struct agnx_sta_traffic {
__le32 reg0;
#define ACK_TIMOUT_CNT 0xFF800000 /* ACK Timeout Counts */
#define ACK_TIMOUT_CNT_SHIFT 23
#define TRAFFIC_ACK_TYPE 0x00600000 /* ACK Type */
#define TRAFFIC_ACK_TYPE_SHIFT 21
#define NEW_PACKET 0x00100000 /* New Packet */
#define NEW_PACKET_SHIFT 20
#define TRAFFIC_VALID 0x00080000 /* Valid */
#define TRAFFIC_VALID_SHIFT 19
#define RX_HDR_DESC_POINTER 0x0007FFFF /* RX Header Descripter pointer */
#define RX_HDR_DESC_POINTER_SHIFT 0
__le32 reg1;
#define RX_PACKET_TIMESTAMP 0xFFFF0000 /* RX Packet Timestamp */
#define RX_PACKET_TIMESTAMP_SHIFT 16
#define TRAFFIC_RESERVED 0x0000E000 /* Reserved */
#define TRAFFIC_RESERVED_SHIFT 13
#define SV 0x00001000 /* sv */
#define SV_SHIFT 12
#define RX_SEQUENCE_NUM 0x00000FFF /* RX Sequence Number */
#define RX_SEQUENCE_NUM_SHIFT 0
__le32 tx_replay_cnt_low; /* TX Replay Counter Low */
__le16 tx_replay_cnt_high; /* TX Replay Counter High */
__le16 rx_replay_cnt_high; /* RX Replay Counter High */
__be32 rx_replay_cnt_low; /* RX Replay Counter Low */
} __attribute__((__packed__));
/*
* Station Descriptors
*/
struct agnx_sta {
__le32 tx_session_keys[4]; /* Transmit Session Key (0-3) */
__le32 rx_session_keys[4]; /* Receive Session Key (0-3) */
__le32 reg;
#define ID_1 0xC0000000 /* id 1 */
#define ID_1_SHIFT 30
#define ID_0 0x30000000 /* id 0 */
#define ID_0_SHIFT 28
#define ENABLE_CONCATENATION 0x0FF00000 /* Enable concatenation */
#define ENABLE_CONCATENATION_SHIFT 20
#define ENABLE_DECOMPRESSION 0x000FF000 /* Enable decompression */
#define ENABLE_DECOMPRESSION_SHIFT 12
#define STA_RESERVED 0x00000C00 /* Reserved */
#define STA_RESERVED_SHIFT 10
#define EAP 0x00000200 /* EAP */
#define EAP_SHIFT 9
#define ED_NULL 0x00000100 /* ED NULL */
#define ED_NULL_SHIFT 8
#define ENCRYPTION_POLICY 0x000000E0 /* Encryption Policy */
#define ENCRYPTION_POLICY_SHIFT 5
#define DEFINED_KEY_ID 0x00000018 /* Defined Key ID */
#define DEFINED_KEY_ID_SHIFT 3
#define FIXED_KEY 0x00000004 /* Fixed Key */
#define FIXED_KEY_SHIFT 2
#define KEY_VALID 0x00000002 /* Key Valid */
#define KEY_VALID_SHIFT 1
#define STATION_VALID 0x00000001 /* Station Valid */
#define STATION_VALID_SHIFT 0
__le32 tx_aes_blks_unicast; /* TX AES Blks Unicast */
__le32 rx_aes_blks_unicast; /* RX AES Blks Unicast */
__le16 aes_format_err_unicast_cnt; /* AES Format Error Unicast Counts */
__le16 aes_replay_unicast; /* AES Replay Unicast */
__le16 aes_decrypt_err_unicast; /* AES Decrypt Error Unicast */
__le16 aes_decrypt_err_default; /* AES Decrypt Error default */
__le16 single_retry_packets; /* Single Retry Packets */
__le16 failed_tx_packets; /* Failed Tx Packets */
__le16 muti_retry_packets; /* Multiple Retry Packets */
__le16 ack_timeouts; /* ACK Timeouts */
__le16 frag_tx_cnt; /* Fragment TX Counts */
__le16 rts_brq_sent; /* RTS Brq Sent */
__le16 tx_packets; /* TX Packets */
__le16 cts_back_timeout; /* CTS Back Timeout */
__le32 phy_stats_high; /* PHY Stats High */
__le32 phy_stats_low; /* PHY Stats Low */
struct agnx_sta_traffic traffic[8]; /* Traffic Class Structure (8) */
__le16 traffic_class0_frag_success; /* Traffic Class 0 Fragment Success */
__le16 traffic_class1_frag_success; /* Traffic Class 1 Fragment Success */
__le16 traffic_class2_frag_success; /* Traffic Class 2 Fragment Success */
__le16 traffic_class3_frag_success; /* Traffic Class 3 Fragment Success */
__le16 traffic_class4_frag_success; /* Traffic Class 4 Fragment Success */
__le16 traffic_class5_frag_success; /* Traffic Class 5 Fragment Success */
__le16 traffic_class6_frag_success; /* Traffic Class 6 Fragment Success */
__le16 traffic_class7_frag_success; /* Traffic Class 7 Fragment Success */
__le16 num_frag_non_prime_rates; /* number of Fragments for non-prime rates */
__le16 ack_timeout_non_prime_rates; /* ACK Timeout for non-prime rates */
} __attribute__((__packed__));
struct agnx_beacon_hdr {
struct agnx_sta_power power; /* Tx Station Power Template */
u8 phy_hdr[6]; /* PHY Hdr */
u8 frame_len_lo; /* Frame Length Lo */
u8 frame_len_hi; /* Frame Length Hi */
u8 mac_hdr[24]; /* MAC Header */
/* FIXME */
/* 802.11(abg) beacon */
} __attribute__((__packed__));
void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id);
void hash_dump(struct agnx_priv *priv, u8 sta_id);
void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id);
void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id);
void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx);
void set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power,
unsigned int sta_idx);
void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
unsigned int sta_idx, unsigned int wq_idx);
void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
unsigned int sta_idx, unsigned int wq_idx);
void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx);
void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx);
void sta_power_init(struct agnx_priv *priv, unsigned int num);
void sta_init(struct agnx_priv *priv, unsigned int num);
#endif /* AGNX_STA_H_ */

View File

@ -0,0 +1,168 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "phy.h"
static const u32
tx_fir_table[] = { 0x19, 0x5d, 0xce, 0x151, 0x1c3, 0x1ff, 0x1ea, 0x17c, 0xcf,
0x19, 0x38e, 0x350, 0x362, 0x3ad, 0x5, 0x44, 0x59, 0x49,
0x21, 0x3f7, 0x3e0, 0x3e3, 0x3f3, 0x0 };
void tx_fir_table_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i < ARRAY_SIZE(tx_fir_table); i++)
iowrite32(tx_fir_table[i], ctl + AGNX_FIR_BASE + i*4);
} /* fir_table_setup */
static const u32
gain_table[] = { 0x8, 0x8, 0xf, 0x13, 0x17, 0x1b, 0x1f, 0x23, 0x27, 0x2b,
0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4b, 0x4f,
0x53, 0x57, 0x5b, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
0x5f, 0x5f, 0x5f, 0x5f };
void gain_table_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
int i;
for (i = 0; i < ARRAY_SIZE(gain_table); i++) {
iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4);
iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4 + 0x80);
}
} /* gain_table_init */
void monitor_gain_table_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
unsigned int i;
for (i = 0; i < 0x44; i += 4) {
iowrite32(0x61, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0x61, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0x44; i < 0x64; i += 4) {
iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0x64; i < 0x94; i += 4) {
iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0x94; i < 0xdc; i += 4) {
iowrite32(0x87, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0x87, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0xdc; i < 0x148; i += 4) {
iowrite32(0x95, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0x95, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0x148; i < 0x1e8; i += 4) {
iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
for (i = 0x1e8; i <= 0x1fc; i += 4) {
iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + i);
iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + 0x200 + i);
}
} /* monitor_gain_table_init */
void routing_table_init(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
unsigned int type, subtype;
u32 reg;
disable_receiver(priv);
for ( type = 0; type < 0x3; type++ ) {
for (subtype = 0; subtype < 0x10; subtype++) {
/* 1. Set Routing table to R/W and to Return status on Read */
reg = (type << ROUTAB_TYPE_SHIFT) |
(subtype << ROUTAB_SUBTYPE_SHIFT);
reg |= (1 << ROUTAB_RW_SHIFT) | (1 << ROUTAB_STATUS_SHIFT);
if (type == ROUTAB_TYPE_DATA) {
/* NULL goes to RFP */
if (subtype == ROUTAB_SUBTYPE_NULL)
// reg |= ROUTAB_ROUTE_RFP;
reg |= ROUTAB_ROUTE_CPU;
/* QOS NULL goes to CPU */
else if (subtype == ROUTAB_SUBTYPE_QOSNULL)
reg |= ROUTAB_ROUTE_CPU;
/* All Data and QOS data subtypes go to Encryption */
else if ((subtype == ROUTAB_SUBTYPE_DATA) ||
(subtype == ROUTAB_SUBTYPE_DATAACK) ||
(subtype == ROUTAB_SUBTYPE_DATAPOLL) ||
(subtype == ROUTAB_SUBTYPE_DATAPOLLACK) ||
(subtype == ROUTAB_SUBTYPE_QOSDATA) ||
(subtype == ROUTAB_SUBTYPE_QOSDATAACK) ||
(subtype == ROUTAB_SUBTYPE_QOSDATAPOLL) ||
(subtype == ROUTAB_SUBTYPE_QOSDATAACKPOLL))
reg |= ROUTAB_ROUTE_ENCRY;
// reg |= ROUTAB_ROUTE_CPU;
/*Drop NULL and QOS NULL ack, poll and poll ack*/
else if ((subtype == ROUTAB_SUBTYPE_NULLACK) ||
(subtype == ROUTAB_SUBTYPE_QOSNULLACK) ||
(subtype == ROUTAB_SUBTYPE_NULLPOLL) ||
(subtype == ROUTAB_SUBTYPE_QOSNULLPOLL) ||
(subtype == ROUTAB_SUBTYPE_NULLPOLLACK) ||
(subtype == ROUTAB_SUBTYPE_QOSNULLPOLLACK))
// reg |= ROUTAB_ROUTE_DROP;
reg |= ROUTAB_ROUTE_CPU;
}
else
reg |= (ROUTAB_ROUTE_CPU);
iowrite32(reg, ctl + AGNX_RXM_ROUTAB);
/* Check to verify that the status bit cleared */
routing_table_delay();
}
}
enable_receiver(priv);
} /* routing_table_init */
void tx_engine_lookup_tbl_init(struct agnx_priv *priv)
{
void __iomem *data = priv->data;
unsigned int i;
for (i = 0; i <= 28; i += 4)
iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i);
for (i = 32; i <= 120; i += 8) {
iowrite32(0x1e58, data + AGNX_ENGINE_LOOKUP_TBL + i);
iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
}
for (i = 128; i <= 156; i += 4)
iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i);
for (i = 160; i <= 248; i += 8) {
iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i);
iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
}
for (i = 256; i <= 284; i += 4)
iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i);
for (i = 288; i <= 376; i += 8) {
iowrite32(0x1a58, data + AGNX_ENGINE_LOOKUP_TBL + i);
iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
}
for (i = 512; i <= 540; i += 4)
iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i);
for (i = 544; i <= 632; i += 8) {
iowrite32(0x2058, data + AGNX_ENGINE_LOOKUP_TBL + i);
iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
}
for (i = 640; i <= 668; i += 4)
iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i);
for (i = 672; i <= 764; i += 8) {
iowrite32(0x2258, data + AGNX_ENGINE_LOOKUP_TBL + i);
iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
}
}

View File

@ -0,0 +1,10 @@
#ifndef AGNX_TABLE_H_
#define AGNX_TABLE_H_
void tx_fir_table_init(struct agnx_priv *priv);
void gain_table_init(struct agnx_priv *priv);
void monitor_gain_table_init(struct agnx_priv *priv);
void routing_table_init(struct agnx_priv *priv);
void tx_engine_lookup_tbl_init(struct agnx_priv *priv);
#endif /* AGNX_TABLE_H_ */

819
drivers/staging/agnx/xmit.c Normal file
View File

@ -0,0 +1,819 @@
/**
* Airgo MIMO wireless driver
*
* Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
* Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
* works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/pci.h>
#include <linux/delay.h>
#include "agnx.h"
#include "debug.h"
#include "phy.h"
unsigned int rx_frame_cnt = 0;
//unsigned int local_tx_sent_cnt = 0;
static inline void disable_rx_engine(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
iowrite32(0x100, ctl + AGNX_CIR_RXCTL);
/* Wait for RX Control to have the Disable Rx Interrupt (0x100) set */
ioread32(ctl + AGNX_CIR_RXCTL);
}
static inline void enable_rx_engine(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
iowrite32(0x80, ctl + AGNX_CIR_RXCTL);
ioread32(ctl + AGNX_CIR_RXCTL);
}
inline void disable_rx_interrupt(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
disable_rx_engine(priv);
reg = ioread32(ctl + AGNX_CIR_RXCFG);
reg &= ~0x20;
iowrite32(reg, ctl + AGNX_CIR_RXCFG);
ioread32(ctl + AGNX_CIR_RXCFG);
}
inline void enable_rx_interrupt(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
u32 reg;
reg = ioread32(ctl + AGNX_CIR_RXCFG);
reg |= 0x20;
iowrite32(reg, ctl + AGNX_CIR_RXCFG);
ioread32(ctl + AGNX_CIR_RXCFG);
enable_rx_engine(priv);
}
static inline void rx_desc_init(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_desc *desc = priv->rx.desc + idx;
struct agnx_info *info = priv->rx.info + idx;
memset(info, 0, sizeof(*info));
info->dma_len = IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct agnx_hdr);
info->skb = dev_alloc_skb(info->dma_len);
if (info->skb == NULL)
agnx_bug("refill err");
info->mapping = pci_map_single(priv->pdev, skb_tail_pointer(info->skb),
info->dma_len, PCI_DMA_FROMDEVICE);
memset(desc, 0, sizeof(*desc));
desc->dma_addr = cpu_to_be32(info->mapping);
/* Set the owner to the card */
desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);
}
static inline void rx_desc_reinit(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_info *info = priv->rx.info + idx;
/* Cause ieee80211 will free the skb buffer, so we needn't to free it again?! */
pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);
rx_desc_init(priv, idx);
}
static inline void rx_desc_reusing(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_desc *desc = priv->rx.desc + idx;
struct agnx_info *info = priv->rx.info + idx;
memset(desc, 0, sizeof(*desc));
desc->dma_addr = cpu_to_be32(info->mapping);
/* Set the owner to the card */
desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);
}
static void rx_desc_free(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_desc *desc = priv->rx.desc + idx;
struct agnx_info *info = priv->rx.info + idx;
BUG_ON(!desc || !info);
if (info->mapping)
pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);
if (info->skb)
dev_kfree_skb(info->skb);
memset(info, 0, sizeof(*info));
memset(desc, 0, sizeof(*desc));
}
static inline void __tx_desc_free(struct agnx_priv *priv,
struct agnx_desc *desc, struct agnx_info *info)
{
BUG_ON(!desc || !info);
/* TODO make sure mapping, skb and len are consistency */
if (info->mapping)
pci_unmap_single(priv->pdev, info->mapping,
info->dma_len, PCI_DMA_TODEVICE);
if (info->type == PACKET)
dev_kfree_skb(info->skb);
memset(info, 0, sizeof(*info));
memset(desc, 0, sizeof(*desc));
}
static void txm_desc_free(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_desc *desc = priv->txm.desc + idx;
struct agnx_info *info = priv->txm.info + idx;
__tx_desc_free(priv, desc, info);
}
static void txd_desc_free(struct agnx_priv *priv, unsigned int idx)
{
struct agnx_desc *desc = priv->txd.desc + idx;
struct agnx_info *info = priv->txd.info + idx;
__tx_desc_free(priv, desc, info);
}
int fill_rings(struct agnx_priv *priv)
{
void __iomem *ctl = priv->ctl;
unsigned int i;
u32 reg;
AGNX_TRACE;
priv->txd.idx_sent = priv->txm.idx_sent = 0;
priv->rx.idx = priv->txm.idx = priv->txd.idx = 0;
for (i = 0; i < priv->rx.size; i++)
rx_desc_init(priv, i);
for (i = 0; i < priv->txm.size; i++) {
memset(priv->txm.desc + i, 0, sizeof(struct agnx_desc));
memset(priv->txm.info + i, 0, sizeof(struct agnx_info));
}
for (i = 0; i < priv->txd.size; i++) {
memset(priv->txd.desc + i, 0, sizeof(struct agnx_desc));
memset(priv->txd.info + i, 0, sizeof(struct agnx_info));
}
/* FIXME Set the card RX TXM and TXD address */
agnx_write32(ctl, AGNX_CIR_RXCMSTART, priv->rx.dma);
agnx_write32(ctl, AGNX_CIR_RXCMEND, priv->txm.dma);
agnx_write32(ctl, AGNX_CIR_TXMSTART, priv->txm.dma);
agnx_write32(ctl, AGNX_CIR_TXMEND, priv->txd.dma);
agnx_write32(ctl, AGNX_CIR_TXDSTART, priv->txd.dma);
agnx_write32(ctl, AGNX_CIR_TXDEND, priv->txd.dma +
sizeof(struct agnx_desc) * priv->txd.size);
/* FIXME Relinquish control of rings to card */
reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
reg &= ~0x800;
agnx_write32(ctl, AGNX_CIR_BLKCTL, reg);
return 0;
} /* fill_rings */
void unfill_rings(struct agnx_priv *priv)
{
unsigned long flags;
unsigned int i;
AGNX_TRACE;
spin_lock_irqsave(&priv->lock, flags);
for (i = 0; i < priv->rx.size; i++)
rx_desc_free(priv, i);
for (i = 0; i < priv->txm.size; i++)
txm_desc_free(priv, i);
for (i = 0; i < priv->txd.size; i++)
txd_desc_free(priv, i);
spin_unlock_irqrestore(&priv->lock, flags);
}
/* Extract the bitrate out of a CCK PLCP header.
copy from bcm43xx driver */
static inline u8 agnx_plcp_get_bitrate_cck(__be32 *phyhdr_11b)
{
/* FIXME */
switch (*(u8 *)phyhdr_11b) {
case 0x0A:
return 0;
case 0x14:
return 1;
case 0x37:
return 2;
case 0x6E:
return 3;
}
agnx_bug("Wrong plcp rate");
return 0;
}
/* FIXME */
static inline u8 agnx_plcp_get_bitrate_ofdm(__be32 *phyhdr_11g)
{
u8 rate = *(u8 *)phyhdr_11g & 0xF;
printk(PFX "G mode rate is 0x%x\n", rate);
return rate;
}
/* FIXME */
static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr,
struct ieee80211_rx_status *stat)
{
void __iomem *ctl = priv->ctl;
u8 *rssi;
u32 noise;
/* FIXME just for test */
int snr = 40; /* signal-to-noise ratio */
memset(stat, 0, sizeof(*stat));
/* RSSI */
rssi = (u8 *)&hdr->phy_stats_lo;
// stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3;
/* Noise */
noise = ioread32(ctl + AGNX_GCR_NOISE0);
noise += ioread32(ctl + AGNX_GCR_NOISE1);
noise += ioread32(ctl + AGNX_GCR_NOISE2);
stat->noise = noise / 3;
/* Signal quality */
//snr = stat->ssi - stat->noise;
if (snr >=0 && snr < 40)
stat->signal = 5 * snr / 2;
else if (snr >= 40)
stat->signal = 100;
else
stat->signal = 0;
if (hdr->_11b0 && !hdr->_11g0) {
stat->rate_idx = agnx_plcp_get_bitrate_cck(&hdr->_11b0);
} else if (!hdr->_11b0 && hdr->_11g0) {
printk(PFX "RX: Found G mode packet\n");
stat->rate_idx = agnx_plcp_get_bitrate_ofdm(&hdr->_11g0);
} else
agnx_bug("Unknown packets type");
stat->band = IEEE80211_BAND_2GHZ;
stat->freq = agnx_channels[priv->channel - 1].center_freq;
// stat->antenna = 3;
// stat->mactime = be32_to_cpu(hdr->time_stamp);
// stat->channel = priv->channel;
}
static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr,
struct sk_buff *skb)
{
u16 fctl;
unsigned int hdrlen;
fctl = le16_to_cpu(ieeehdr->frame_control);
hdrlen = ieee80211_hdrlen(fctl);
/* FIXME */
if (hdrlen < (2+2+6)/*minimum hdr*/ ||
hdrlen > sizeof(struct ieee80211_mgmt)) {
printk(KERN_ERR PFX "hdr len is %d\n", hdrlen);
agnx_bug("Wrong ieee80211 hdr detected");
}
skb_push(skb, hdrlen);
memcpy(skb->data, ieeehdr, hdrlen);
} /* combine_hdr_frag */
static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr,
unsigned packet_len)
{
if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1){
printk(PFX "RX: CRC check fail\n");
goto drop;
}
if (packet_len > 2048) {
printk(PFX "RX: Too long packet detected\n");
goto drop;
}
/* FIXME Just usable for Promious Mode, for Manage mode exclude FCS */
/* if (packet_len - sizeof(*agnxhdr) < FCS_LEN) { */
/* printk(PFX "RX: Too short packet detected\n"); */
/* goto drop; */
/* } */
return 0;
drop:
priv->stats.dot11FCSErrorCount++;
return -1;
}
void handle_rx_irq(struct agnx_priv *priv)
{
struct ieee80211_rx_status status;
unsigned int len;
// AGNX_TRACE;
do {
struct agnx_desc *desc;
u32 frag;
struct agnx_info *info;
struct agnx_hdr *hdr;
struct sk_buff *skb;
unsigned int i = priv->rx.idx % priv->rx.size;
desc = priv->rx.desc + i;
frag = be32_to_cpu(desc->frag);
if (frag & OWNER)
break;
info = priv->rx.info + i;
skb = info->skb;
hdr = (struct agnx_hdr *)(skb->data);
len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT;
if (agnx_packet_check(priv, hdr, len) == -1) {
rx_desc_reusing(priv, i);
continue;
}
skb_put(skb, len);
do {
u16 fctl;
fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control);
if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)// && !(fctl & IEEE80211_STYPE_BEACON))
dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX");
} while (0);
if (hdr->_11b0 && !hdr->_11g0) {
/* int j; */
/* u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr) */
/* ->frame_control); */
/* if ( (fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { */
/* agnx_print_rx_hdr(hdr); */
// agnx_print_sta(priv, BSSID_STAID);
/* for (j = 0; j < 8; j++) */
/* agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */
/* } */
get_rx_stats(priv, hdr, &status);
skb_pull(skb, sizeof(*hdr));
combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb);
} else if (!hdr->_11b0 && hdr->_11g0) {
// int j;
agnx_print_rx_hdr(hdr);
agnx_print_sta(priv, BSSID_STAID);
// for (j = 0; j < 8; j++)
agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE,
skb->data, skb->len + 8);
// if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0)
get_rx_stats(priv, hdr, &status);
skb_pull(skb, sizeof(*hdr));
combine_hdr_frag((struct ieee80211_hdr *)
((void *)&hdr->mac_hdr), skb);
// dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G");
} else
agnx_bug("Unknown packets type");
ieee80211_rx_irqsafe(priv->hw, skb, &status);
rx_desc_reinit(priv, i);
} while ( priv->rx.idx++ );
} /* handle_rx_irq */
static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
{
struct agnx_desc *desc;
struct agnx_info *info;
unsigned int idx;
for (idx = ring->idx_sent; idx < ring->idx; idx++) {
unsigned int i = idx % ring->size;
u32 frag;
desc = ring->desc + i;
info = ring->info + i;
frag = be32_to_cpu(desc->frag);
if (frag & OWNER) {
if (info->type == HEADER)
break;
else
agnx_bug("TX error");
}
pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_TODEVICE);
do {
// int j;
size_t len;
len = info->skb->len - sizeof(struct agnx_hdr) + info->hdr_len;
// if (len == 614) {
// agnx_print_desc(desc);
if (info->type == PACKET) {
// agnx_print_tx_hdr((struct agnx_hdr *)info->skb->data);
/* agnx_print_sta_power(priv, LOCAL_STAID); */
/* agnx_print_sta(priv, LOCAL_STAID); */
/* // for (j = 0; j < 8; j++) */
/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, 0); */
// agnx_print_sta_power(priv, BSSID_STAID);
// agnx_print_sta(priv, BSSID_STAID);
// for (j = 0; j < 8; j++)
// agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
}
// }
} while (0);
if (info->type == PACKET) {
// dump_txm_registers(priv);
// dump_rxm_registers(priv);
// dump_bm_registers(priv);
// dump_cir_registers(priv);
}
if (info->type == PACKET) {
// struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(info->skb);
skb_pull(info->skb, sizeof(struct agnx_hdr));
memcpy(skb_push(info->skb, info->hdr_len), &info->hdr, info->hdr_len);
// dump_ieee80211_hdr((struct ieee80211_hdr *)info->skb->data, "TX_HANDLE");
/* print_hex_dump_bytes("agnx: TX_HANDLE: ", DUMP_PREFIX_NONE, */
/* info->skb->data, info->skb->len); */
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK))
txi->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(priv->hw, info->skb);
/* info->tx_status.queue_number = (ring->size - i) / 2; */
/* ieee80211_tx_status_irqsafe(priv->hw, info->skb, &(info->tx_status)); */
/* } else */
/* dev_kfree_skb_irq(info->skb); */
}
memset(desc, 0, sizeof(*desc));
memset(info, 0, sizeof(*info));
}
ring->idx_sent = idx;
/* TODO fill the priv->low_level_stats */
/* ieee80211_wake_queue(priv->hw, 0); */
}
void handle_txm_irq(struct agnx_priv *priv)
{
handle_tx_irq(priv, &priv->txm);
}
void handle_txd_irq(struct agnx_priv *priv)
{
handle_tx_irq(priv, &priv->txd);
}
void handle_other_irq(struct agnx_priv *priv)
{
// void __iomem *ctl = priv->ctl;
u32 status = priv->irq_status;
void __iomem *ctl = priv->ctl;
u32 reg;
if (status & IRQ_TX_BEACON) {
iowrite32(IRQ_TX_BEACON, ctl + AGNX_INT_STAT);
printk(PFX "IRQ: TX Beacon control is 0X%.8X\n", ioread32(ctl + AGNX_TXM_BEACON_CTL));
printk(PFX "IRQ: TX Beacon rx frame num: %d\n", rx_frame_cnt);
}
if (status & IRQ_TX_RETRY) {
reg = ioread32(ctl + AGNX_TXM_RETRYSTAID);
printk(PFX "IRQ: TX Retry, RETRY STA ID is %x\n", reg);
}
if (status & IRQ_TX_ACTIVITY)
printk(PFX "IRQ: TX Activity\n");
if (status & IRQ_RX_ACTIVITY)
printk(PFX "IRQ: RX Activity\n");
if (status & IRQ_RX_X)
printk(PFX "IRQ: RX X\n");
if (status & IRQ_RX_Y) {
reg = ioread32(ctl + AGNX_INT_MASK);
reg &= ~IRQ_RX_Y;
iowrite32(reg, ctl + AGNX_INT_MASK);
iowrite32(IRQ_RX_Y, ctl + AGNX_INT_STAT);
printk(PFX "IRQ: RX Y\n");
}
if (status & IRQ_RX_HASHHIT) {
reg = ioread32(ctl + AGNX_INT_MASK);
reg &= ~IRQ_RX_HASHHIT;
iowrite32(reg, ctl + AGNX_INT_MASK);
iowrite32(IRQ_RX_HASHHIT, ctl + AGNX_INT_STAT);
printk(PFX "IRQ: RX Hash Hit\n");
}
if (status & IRQ_RX_FRAME) {
reg = ioread32(ctl + AGNX_INT_MASK);
reg &= ~IRQ_RX_FRAME;
iowrite32(reg, ctl + AGNX_INT_MASK);
iowrite32(IRQ_RX_FRAME, ctl + AGNX_INT_STAT);
printk(PFX "IRQ: RX Frame\n");
rx_frame_cnt++;
}
if (status & IRQ_ERR_INT) {
iowrite32(IRQ_ERR_INT, ctl + AGNX_INT_STAT);
// agnx_hw_reset(priv);
printk(PFX "IRQ: Error Interrupt\n");
}
if (status & IRQ_TX_QUE_FULL)
printk(PFX "IRQ: TX Workqueue Full\n");
if (status & IRQ_BANDMAN_ERR)
printk(PFX "IRQ: Bandwidth Management Error\n");
if (status & IRQ_TX_DISABLE)
printk(PFX "IRQ: TX Disable\n");
if (status & IRQ_RX_IVASESKEY)
printk(PFX "IRQ: RX Invalid Session Key\n");
if (status & IRQ_REP_THHIT)
printk(PFX "IRQ: Replay Threshold Hit\n");
if (status & IRQ_TIMER1)
printk(PFX "IRQ: Timer1\n");
if (status & IRQ_TIMER_CNT)
printk(PFX "IRQ: Timer Count\n");
if (status & IRQ_PHY_FASTINT)
printk(PFX "IRQ: Phy Fast Interrupt\n");
if (status & IRQ_PHY_SLOWINT)
printk(PFX "IRQ: Phy Slow Interrupt\n");
if (status & IRQ_OTHER)
printk(PFX "IRQ: 0x80000000\n");
} /* handle_other_irq */
static inline void route_flag_set(struct agnx_hdr *txhdr)
{
// u32 reg = 0;
/* FIXME */
/* reg = (0x7 << ROUTE_COMPRESSION_SHIFT) & ROUTE_COMPRESSION; */
/* txhdr->reg5 = cpu_to_be32(reg); */
txhdr->reg5 = (0xa << 0x0) | (0x7 << 0x18);
// txhdr->reg5 = cpu_to_be32((0xa << 0x0) | (0x7 << 0x18));
// txhdr->reg5 = cpu_to_be32(0x7 << 0x0);
}
/* Return 0 if no match */
static inline unsigned int get_power_level(unsigned int rate, unsigned int antennas_num)
{
unsigned int power_level;
switch (rate) {
case 10:
case 20:
case 55:
case 60:
case 90:
case 120: power_level = 22; break;
case 180: power_level = 19; break;
case 240: power_level = 18; break;
case 360: power_level = 16; break;
case 480: power_level = 15; break;
case 540: power_level = 14; break;
default:
agnx_bug("Error rate setting\n");
}
if (power_level && (antennas_num == 2))
power_level -= 3;
return power_level;
}
static inline void fill_agnx_hdr(struct agnx_priv *priv, struct agnx_info *tx_info)
{
struct agnx_hdr *txhdr = (struct agnx_hdr *)tx_info->skb->data;
size_t len;
u16 fc = le16_to_cpu(*(__le16 *)&tx_info->hdr);
u32 reg;
memset(txhdr, 0, sizeof(*txhdr));
// reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, LOCAL_STAID);
reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, BSSID_STAID);
reg |= agnx_set_bits(WORKQUEUE_ID, WORKQUEUE_ID_SHIFT, 0);
txhdr->reg4 = cpu_to_be32(reg);
/* Set the Hardware Sequence Number to 1? */
reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 0);
// reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 1);
reg |= agnx_set_bits(MAC_HDR_LEN, MAC_HDR_LEN_SHIFT, tx_info->hdr_len);
txhdr->reg1 = cpu_to_be32(reg);
/* Set the agnx_hdr's MAC header */
memcpy(txhdr->mac_hdr, &tx_info->hdr, tx_info->hdr_len);
reg = agnx_set_bits(ACK, ACK_SHIFT, 1);
// reg = agnx_set_bits(ACK, ACK_SHIFT, 0);
reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 0);
// reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 1);
reg |= agnx_set_bits(RELAY, RELAY_SHIFT, 0);
reg |= agnx_set_bits(TM, TM_SHIFT, 0);
txhdr->reg0 = cpu_to_be32(reg);
/* Set the long and short retry limits */
txhdr->tx.short_retry_limit = tx_info->txi->control.retry_limit;
txhdr->tx.long_retry_limit = tx_info->txi->control.retry_limit;
/* FIXME */
len = tx_info->skb->len - sizeof(*txhdr) + tx_info->hdr_len + FCS_LEN;
if (fc & IEEE80211_FCTL_PROTECTED)
len += 8;
len = 2398;
reg = agnx_set_bits(FRAG_SIZE, FRAG_SIZE_SHIFT, len);
len = tx_info->skb->len - sizeof(*txhdr);
reg |= agnx_set_bits(PAYLOAD_LEN, PAYLOAD_LEN_SHIFT, len);
txhdr->reg3 = cpu_to_be32(reg);
route_flag_set(txhdr);
} /* fill_hdr */
static void txm_power_set(struct agnx_priv *priv,
struct ieee80211_tx_info *txi)
{
struct agnx_sta_power power;
u32 reg;
/* FIXME */
if (txi->tx_rate_idx < 0) {
/* For B mode Short Preamble */
reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_SHORT);
// control->tx_rate = -control->tx_rate;
} else
reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211G);
// reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_LONG);
reg |= agnx_set_bits(SIGNAL, SIGNAL_SHIFT, 0xB);
reg |= agnx_set_bits(RATE, RATE_SHIFT, 0xB);
// reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 15);
reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 20);
/* if rate < 11M set it to 0 */
reg |= agnx_set_bits(NUM_TRANSMITTERS, NUM_TRANSMITTERS_SHIFT, 1);
// reg |= agnx_set_bits(EDCF, EDCF_SHIFT, 1);
// reg |= agnx_set_bits(TIFS, TIFS_SHIFT, 1);
power.reg = reg;
// power.reg = cpu_to_le32(reg);
// set_sta_power(priv, &power, LOCAL_STAID);
set_sta_power(priv, &power, BSSID_STAID);
}
static inline int tx_packet_check(struct sk_buff *skb)
{
unsigned int ieee_len = ieee80211_get_hdrlen_from_skb(skb);
if (skb->len > 2048) {
printk(KERN_ERR PFX "length is %d\n", skb->len);
agnx_bug("Too long TX skb");
return -1;
}
/* FIXME */
if (skb->len == ieee_len) {
printk(PFX "A strange TX packet\n");
return -1;
/* tx_faile_irqsafe(); */
}
return 0;
}
static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb,
struct agnx_ring *ring)
{
struct agnx_desc *hdr_desc, *frag_desc;
struct agnx_info *hdr_info, *frag_info;
struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
unsigned long flags;
unsigned int i;
spin_lock_irqsave(&priv->lock, flags);
/* The RX interrupt need be Disable until this TX packet
is handled in the next tx interrupt */
disable_rx_interrupt(priv);
i = ring->idx;
ring->idx += 2;
/* if (priv->txm_idx - priv->txm_idx_sent == AGNX_TXM_RING_SIZE - 2) */
/* ieee80211_stop_queue(priv->hw, 0); */
/* Set agnx header's info and desc */
i %= ring->size;
hdr_desc = ring->desc + i;
hdr_info = ring->info + i;
hdr_info->hdr_len = ieee80211_get_hdrlen_from_skb(skb);
memcpy(&hdr_info->hdr, skb->data, hdr_info->hdr_len);
/* Add the agnx header to the front of the SKB */
skb_push(skb, sizeof(struct agnx_hdr) - hdr_info->hdr_len);
hdr_info->txi = txi;
hdr_info->dma_len = sizeof(struct agnx_hdr);
hdr_info->skb = skb;
hdr_info->type = HEADER;
fill_agnx_hdr(priv, hdr_info);
hdr_info->mapping = pci_map_single(priv->pdev, skb->data,
hdr_info->dma_len, PCI_DMA_TODEVICE);
do {
u32 frag = 0;
frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 1);
frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 0);
frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len);
frag |= agnx_set_bits(FIRST_FRAG_LEN, FIRST_FRAG_LEN_SHIFT, 1);
frag |= agnx_set_bits(OWNER, OWNER_SHIFT, 1);
hdr_desc->frag = cpu_to_be32(frag);
} while (0);
hdr_desc->dma_addr = cpu_to_be32(hdr_info->mapping);
/* Set Frag's info and desc */
i = (i + 1) % ring->size;
frag_desc = ring->desc + i;
frag_info = ring->info + i;
memcpy(frag_info, hdr_info, sizeof(struct agnx_info));
frag_info->type = PACKET;
frag_info->dma_len = skb->len - hdr_info->dma_len;
frag_info->mapping = pci_map_single(priv->pdev, skb->data + hdr_info->dma_len,
frag_info->dma_len, PCI_DMA_TODEVICE);
do {
u32 frag = 0;
frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 0);
frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 1);
frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len);
frag |= agnx_set_bits(SUB_FRAG_LEN, SUB_FRAG_LEN_SHIFT, frag_info->dma_len);
frag_desc->frag = cpu_to_be32(frag);
} while (0);
frag_desc->dma_addr = cpu_to_be32(frag_info->mapping);
txm_power_set(priv, txi);
/* do { */
/* int j; */
/* size_t len; */
/* len = skb->len - hdr_info->dma_len + hdr_info->hdr_len; */
/* // if (len == 614) { */
/* agnx_print_desc(hdr_desc); */
/* agnx_print_desc(frag_desc); */
/* agnx_print_tx_hdr((struct agnx_hdr *)skb->data); */
/* agnx_print_sta_power(priv, LOCAL_STAID); */
/* agnx_print_sta(priv, LOCAL_STAID); */
/* for (j = 0; j < 8; j++) */
/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, j); */
/* agnx_print_sta_power(priv, BSSID_STAID); */
/* agnx_print_sta(priv, BSSID_STAID); */
/* for (j = 0; j < 8; j++) */
/* agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */
/* // } */
/* } while (0); */
spin_unlock_irqrestore(&priv->lock, flags);
/* FIXME ugly code */
/* Trigger TXM */
do {
u32 reg;
reg = (ioread32(priv->ctl + AGNX_CIR_TXMCTL));
reg |= 0x8;
iowrite32((reg), priv->ctl + AGNX_CIR_TXMCTL);
}while (0);
/* Trigger TXD */
do {
u32 reg;
reg = (ioread32(priv->ctl + AGNX_CIR_TXDCTL));
reg |= 0x8;
iowrite32((reg), priv->ctl + AGNX_CIR_TXDCTL);
}while (0);
return 0;
}
int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb)
{
u16 fctl;
if (tx_packet_check(skb))
return 0;
/* print_hex_dump_bytes("agnx: TX_PACKET: ", DUMP_PREFIX_NONE, */
/* skb->data, skb->len); */
fctl = le16_to_cpu(*((__le16 *)skb->data));
if ( (fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA )
return __agnx_tx(priv, skb, &priv->txd);
else
return __agnx_tx(priv, skb, &priv->txm);
}

250
drivers/staging/agnx/xmit.h Normal file
View File

@ -0,0 +1,250 @@
#ifndef AGNX_XMIT_H_
#define AGNX_XMIT_H_
#include <net/mac80211.h>
struct agnx_priv;
static inline u32 agnx_set_bits(u32 mask, u8 shift, u32 value)
{
return (value << shift) & mask;
}
static inline u32 agnx_get_bits(u32 mask, u8 shift, u32 value)
{
return (value & mask) >> shift;
}
struct agnx_rx {
__be16 rx_packet_duration; /* RX Packet Duration */
__be16 replay_cnt; /* Replay Count */
} __attribute__((__packed__));
struct agnx_tx {
u8 long_retry_limit; /* Long Retry Limit */
u8 short_retry_limit; /* Short Retry Limit */
u8 long_retry_cnt; /* Long Retry Count */
u8 short_retry_cnt; /* Short Retry Count */
} __attribute__((__packed__));
/* Copy from bcm43xx */
#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__, nr_bytes)
#define P4D_BIT3S(magic, nr_bits) __be32 __padding##magic:nr_bits
#define P4D_BITS(line, nr_bits) P4D_BIT3S(line, nr_bits)
#define PAD_BITS(nr_bits) P4D_BITS(__LINE__, nr_bits)
struct agnx_hdr {
__be32 reg0;
#define RTS 0x80000000 /* RTS */
#define RTS_SHIFT 31
#define MULTICAST 0x40000000 /* multicast */
#define MULTICAST_SHIFT 30
#define ACK 0x30000000 /* ACK */
#define ACK_SHIFT 28
#define TM 0x08000000 /* TM */
#define TM_SHIFT 27
#define RELAY 0x04000000 /* Relay */
#define RELAY_SHIFT 26
/* PAD_BITS(4); */
#define REVISED_FCS 0x00380000 /* revised FCS */
#define REVISED_FCS_SHIFT 19
#define NEXT_BUFFER_ADDR 0x0007FFFF /* Next Buffer Address */
#define NEXT_BUFFER_ADDR_SHIFT 0
__be32 reg1;
#define MAC_HDR_LEN 0xFC000000 /* MAC Header Length */
#define MAC_HDR_LEN_SHIFT 26
#define DURATION_OVERIDE 0x02000000 /* Duration Override */
#define DURATION_OVERIDE_SHIFT 25
#define PHY_HDR_OVERIDE 0x01000000 /* PHY Header Override */
#define PHY_HDR_OVERIDE_SHIFT 24
#define CRC_FAIL 0x00800000 /* CRC fail */
#define CRC_FAIL_SHIFT 23
/* PAD_BITS(1); */
#define SEQUENCE_NUMBER 0x00200000 /* Sequence Number */
#define SEQUENCE_NUMBER_SHIFT 21
/* PAD_BITS(2); */
#define BUFF_HEAD_ADDR 0x0007FFFF /* Buffer Head Address */
#define BUFF_HEAD_ADDR_SHIFT 0
__be32 reg2;
#define PDU_COUNT 0xFC000000 /* PDU Count */
#define PDU_COUNT_SHIFT 26
/* PAD_BITS(3); */
#define WEP_KEY 0x00600000 /* WEP Key # */
#define WEP_KEY_SHIFT 21
#define USES_WEP_KEY 0x00100000 /* Uses WEP Key */
#define USES_WEP_KEY_SHIFT 20
#define KEEP_ALIVE 0x00080000 /* Keep alive */
#define KEEP_ALIVE_SHIFT 19
#define BUFF_TAIL_ADDR 0x0007FFFF /* Buffer Tail Address */
#define BUFF_TAIL_ADDR_SHIFT 0
__be32 reg3;
#define CTS_11G 0x80000000 /* CTS in 11g */
#define CTS_11G_SHIFT 31
#define RTS_11G 0x40000000 /* RTS in 11g */
#define RTS_11G_SHIFT 30
/* PAD_BITS(2); */
#define FRAG_SIZE 0x0FFF0000 /* fragment size */
#define FRAG_SIZE_SHIFT 16
#define PAYLOAD_LEN 0x0000FFF0 /* payload length */
#define PAYLOAD_LEN_SHIFT 4
#define FRAG_NUM 0x0000000F /* number of frags */
#define FRAG_NUM_SHIFT 0
__be32 reg4;
/* PAD_BITS(4); */
#define RELAY_STAID 0x0FFF0000 /* relayStald */
#define RELAY_STAID_SHIFT 16
#define STATION_ID 0x0000FFF0 /* Station ID */
#define STATION_ID_SHIFT 4
#define WORKQUEUE_ID 0x0000000F /* Workqueue ID */
#define WORKQUEUE_ID_SHIFT 0
/* FIXME this register maybe is LE? */
__be32 reg5;
/* PAD_BITS(4); */
#define ROUTE_HOST 0x0F000000
#define ROUTE_HOST_SHIFT 24
#define ROUTE_CARD_CPU 0x00F00000
#define ROUTE_CARD_CPU_SHIFT 20
#define ROUTE_ENCRYPTION 0x000F0000
#define ROUTE_ENCRYPTION_SHIFT 16
#define ROUTE_TX 0x0000F000
#define ROUTE_TX_SHIFT 12
#define ROUTE_RX1 0x00000F00
#define ROUTE_RX1_SHIFT 8
#define ROUTE_RX2 0x000000F0
#define ROUTE_RX2_SHIFT 4
#define ROUTE_COMPRESSION 0x0000000F
#define ROUTE_COMPRESSION_SHIFT 0
__be32 _11g0; /* 11g */
__be32 _11g1; /* 11g */
__be32 _11b0; /* 11b */
__be32 _11b1; /* 11b */
u8 mac_hdr[32]; /* MAC header */
__be16 rts_duration; /* RTS duration */
__be16 last_duration; /* Last duration */
__be16 sec_last_duration; /* Second to Last duration */
__be16 other_duration; /* Other duration */
__be16 tx_last_duration; /* TX Last duration */
__be16 tx_other_duration; /* TX Other Duration */
__be16 last_11g_len; /* Length of last 11g */
__be16 other_11g_len; /* Lenght of other 11g */
__be16 last_11b_len; /* Length of last 11b */
__be16 other_11b_len; /* Lenght of other 11b */
__be16 reg6;
#define MBF 0xF000 /* mbf */
#define MBF_SHIFT 12
#define RSVD4 0x0FFF /* rsvd4 */
#define RSVD4_SHIFT 0
__be16 rx_frag_stat; /* RX fragmentation status */
__be32 time_stamp; /* TimeStamp */
__be32 phy_stats_hi; /* PHY stats hi */
__be32 phy_stats_lo; /* PHY stats lo */
__be32 mic_key0; /* MIC key 0 */
__be32 mic_key1; /* MIC key 1 */
union { /* RX/TX Union */
struct agnx_rx rx;
struct agnx_tx tx;
};
u8 rx_channel; /* Recieve Channel */
PAD_BYTES(3);
u8 reserved[4];
} __attribute__((__packed__));
struct agnx_desc {
#define PACKET_LEN 0xFFF00000
#define PACKET_LEN_SHIFT 20
/* ------------------------------------------------ */
#define FIRST_PACKET_MASK 0x00080000
#define FIRST_PACKET_MASK_SHIFT 19
#define FIRST_RESERV2 0x00040000
#define FIRST_RESERV2_SHIFT 18
#define FIRST_TKIP_ERROR 0x00020000
#define FIRST_TKIP_ERROR_SHIFT 17
#define FIRST_TKIP_PACKET 0x00010000
#define FIRST_TKIP_PACKET_SHIFT 16
#define FIRST_RESERV1 0x0000F000
#define FIRST_RESERV1_SHIFT 12
#define FIRST_FRAG_LEN 0x00000FF8
#define FIRST_FRAG_LEN_SHIFT 3
/* ------------------------------------------------ */
#define SUB_RESERV2 0x000c0000
#define SUB_RESERV2_SHIFT 18
#define SUB_TKIP_ERROR 0x00020000
#define SUB_TKIP_ERROR_SHIFT 17
#define SUB_TKIP_PACKET 0x00010000
#define SUB_TKIP_PACKET_SHIFT 16
#define SUB_RESERV1 0x00008000
#define SUB_RESERV1_SHIFT 15
#define SUB_FRAG_LEN 0x00007FF8
#define SUB_FRAG_LEN_SHIFT 3
/* ------------------------------------------------ */
#define FIRST_FRAG 0x00000004
#define FIRST_FRAG_SHIFT 2
#define LAST_FRAG 0x00000002
#define LAST_FRAG_SHIFT 1
#define OWNER 0x00000001
#define OWNER_SHIFT 0
__be32 frag;
__be32 dma_addr;
} __attribute__((__packed__));
enum {HEADER, PACKET};
struct agnx_info {
struct sk_buff *skb;
dma_addr_t mapping;
u32 dma_len; /* dma buffer len */
/* Below fields only usful for tx */
u32 hdr_len; /* ieee80211 header length */
unsigned int type;
struct ieee80211_tx_info *txi;
struct ieee80211_hdr hdr;
};
struct agnx_ring {
struct agnx_desc *desc;
dma_addr_t dma;
struct agnx_info *info;
/* Will lead to overflow when sent packet number enough? */
unsigned int idx;
unsigned int idx_sent; /* only usful for txd and txm */
unsigned int size;
};
#define AGNX_RX_RING_SIZE 128
#define AGNX_TXD_RING_SIZE 256
#define AGNX_TXM_RING_SIZE 128
void disable_rx_interrupt(struct agnx_priv *priv);
void enable_rx_interrupt(struct agnx_priv *priv);
int fill_rings(struct agnx_priv *priv);
void unfill_rings(struct agnx_priv *priv);
void handle_rx_irq(struct agnx_priv *priv);
void handle_txd_irq(struct agnx_priv *priv);
void handle_txm_irq(struct agnx_priv *priv);
void handle_other_irq(struct agnx_priv *priv);
int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb);
#endif /* AGNX_XMIT_H_ */