220 lines
6.5 KiB
C
220 lines
6.5 KiB
C
|
#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 */
|
||
|
|
||
|
|