summaryrefslogtreecommitdiff
path: root/drivers/staging/agnx/sta.c
diff options
context:
space:
mode:
authorLi YanBo <dreamfly281@gmail.com>2008-10-27 20:32:57 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-06 13:52:09 -0800
commit0f22aab89715916c100b5fa7d146c497d99d45ca (patch)
treec8874b46043e91df08ee8e2273a8bd74f60aa587 /drivers/staging/agnx/sta.c
parent470c5736fffa16923a3d27a0f365b691086a014d (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.c219
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 */
+
+