| #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 */ |
| |
| |