diff options
author | Li YanBo <dreamfly281@gmail.com> | 2008-10-27 20:32:57 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-06 13:52:09 -0800 |
commit | 0f22aab89715916c100b5fa7d146c497d99d45ca (patch) | |
tree | c8874b46043e91df08ee8e2273a8bd74f60aa587 /drivers/staging/agnx/sta.c | |
parent | 470c5736fffa16923a3d27a0f365b691086a014d (diff) |
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>
Diffstat (limited to 'drivers/staging/agnx/sta.c')
-rw-r--r-- | drivers/staging/agnx/sta.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/drivers/staging/agnx/sta.c b/drivers/staging/agnx/sta.c new file mode 100644 index 000000000000..d3ac675e45bd --- /dev/null +++ b/drivers/staging/agnx/sta.c @@ -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 */ + + |