Commit dc33b251 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau

mt76: move mac beacon routines in mt76x02-lib module

Move mt76x02_beacon mac routines in mt76x02_mac.c in
order to be reused by mt76x0 driver adding AP support
Signed-off-by: default avatarLorenzo Bianconi <lorenzo.bianconi@redhat.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 5cbace02
......@@ -794,3 +794,126 @@ void mt76x02_mac_work(struct work_struct *work)
MT_CALIBRATE_INTERVAL);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_work);
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
{
idx &= 7;
mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr));
mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR,
get_unaligned_le16(addr + 4));
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_bssid);
static int
mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
{
int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
struct mt76x02_txwi txwi;
if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
return -ENOSPC;
mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
offset += sizeof(txwi);
mt76_wr_copy(dev, offset, skb->data, skb->len);
return 0;
}
static int
__mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx,
struct sk_buff *skb)
{
int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
int ret = 0;
int i;
/* Prevent corrupt transmissions during update */
mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
if (skb) {
ret = mt76x02_write_beacon(dev, beacon_addr, skb);
if (!ret)
dev->beacon_data_mask |= BIT(bcn_idx);
} else {
dev->beacon_data_mask &= ~BIT(bcn_idx);
for (i = 0; i < beacon_len; i += 4)
mt76_wr(dev, beacon_addr + i, 0);
}
mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
return ret;
}
int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb)
{
bool force_update = false;
int bcn_idx = 0;
int i;
for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
if (vif_idx == i) {
force_update = !!dev->beacons[i] ^ !!skb;
if (dev->beacons[i])
dev_kfree_skb(dev->beacons[i]);
dev->beacons[i] = skb;
__mt76x02_mac_set_beacon(dev, bcn_idx, skb);
} else if (force_update && dev->beacons[i]) {
__mt76x02_mac_set_beacon(dev, bcn_idx,
dev->beacons[i]);
}
bcn_idx += !!dev->beacons[i];
}
for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
if (!(dev->beacon_data_mask & BIT(i)))
break;
__mt76x02_mac_set_beacon(dev, i, NULL);
}
mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
bcn_idx - 1);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
u8 vif_idx, bool val)
{
u8 old_mask = dev->beacon_mask;
bool en;
u32 reg;
if (val) {
dev->beacon_mask |= BIT(vif_idx);
} else {
dev->beacon_mask &= ~BIT(vif_idx);
mt76x02_mac_set_beacon(dev, vif_idx, NULL);
}
if (!!old_mask == !!dev->beacon_mask)
return;
en = dev->beacon_mask;
mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
reg = MT_BEACON_TIME_CFG_BEACON_TX |
MT_BEACON_TIME_CFG_TBTT_EN |
MT_BEACON_TIME_CFG_TIMER_EN;
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
if (en)
mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
else
mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon_enable);
......@@ -227,4 +227,10 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush);
void mt76x02_update_channel(struct mt76_dev *mdev);
void mt76x02_mac_work(struct work_struct *work);
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb);
void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
bool val);
#endif
......@@ -26,10 +26,5 @@ struct mt76x02_vif;
int mt76x2_mac_start(struct mt76x02_dev *dev);
void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force);
void mt76x2_mac_resume(struct mt76x02_dev *dev);
void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb);
void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, bool val);
#endif
......@@ -153,8 +153,8 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
mt76x02_mac_shared_key_setup(dev, i, k, NULL);
for (i = 0; i < 8; i++) {
mt76x2_mac_set_bssid(dev, i, null_addr);
mt76x2_mac_set_beacon(dev, i, NULL);
mt76x02_mac_set_bssid(dev, i, null_addr);
mt76x02_mac_set_beacon(dev, i, NULL);
}
for (i = 0; i < 16; i++)
......
......@@ -19,124 +19,6 @@
#include "mcu.h"
#include "eeprom.h"
void mt76x2_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
{
idx &= 7;
mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr));
mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR,
get_unaligned_le16(addr + 4));
}
static int
mt76_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
{
int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
struct mt76x02_txwi txwi;
if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
return -ENOSPC;
mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
offset += sizeof(txwi);
mt76_wr_copy(dev, offset, skb->data, skb->len);
return 0;
}
static int
__mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, struct sk_buff *skb)
{
int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
int ret = 0;
int i;
/* Prevent corrupt transmissions during update */
mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
if (skb) {
ret = mt76_write_beacon(dev, beacon_addr, skb);
if (!ret)
dev->beacon_data_mask |= BIT(bcn_idx);
} else {
dev->beacon_data_mask &= ~BIT(bcn_idx);
for (i = 0; i < beacon_len; i += 4)
mt76_wr(dev, beacon_addr + i, 0);
}
mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
return ret;
}
int mt76x2_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
struct sk_buff *skb)
{
bool force_update = false;
int bcn_idx = 0;
int i;
for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
if (vif_idx == i) {
force_update = !!dev->beacons[i] ^ !!skb;
if (dev->beacons[i])
dev_kfree_skb(dev->beacons[i]);
dev->beacons[i] = skb;
__mt76x2_mac_set_beacon(dev, bcn_idx, skb);
} else if (force_update && dev->beacons[i]) {
__mt76x2_mac_set_beacon(dev, bcn_idx, dev->beacons[i]);
}
bcn_idx += !!dev->beacons[i];
}
for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
if (!(dev->beacon_data_mask & BIT(i)))
break;
__mt76x2_mac_set_beacon(dev, i, NULL);
}
mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
bcn_idx - 1);
return 0;
}
void mt76x2_mac_set_beacon_enable(struct mt76x02_dev *dev,
u8 vif_idx, bool val)
{
u8 old_mask = dev->beacon_mask;
bool en;
u32 reg;
if (val) {
dev->beacon_mask |= BIT(vif_idx);
} else {
dev->beacon_mask &= ~BIT(vif_idx);
mt76x2_mac_set_beacon(dev, vif_idx, NULL);
}
if (!!old_mask == !!dev->beacon_mask)
return;
en = dev->beacon_mask;
mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
reg = MT_BEACON_TIME_CFG_BEACON_TX |
MT_BEACON_TIME_CFG_TBTT_EN |
MT_BEACON_TIME_CFG_TIMER_EN;
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
if (en)
mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
else
mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
}
void mt76x2_mac_set_tx_protection(struct mt76x02_dev *dev, u32 val)
{
u32 data = 0;
......
......@@ -137,7 +137,7 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&dev->mt76.mutex);
if (changed & BSS_CHANGED_BSSID)
mt76x2_mac_set_bssid(dev, mvif->idx, info->bssid);
mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid);
if (changed & BSS_CHANGED_BEACON_INT) {
mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
......@@ -149,8 +149,8 @@ mt76x2_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changed & BSS_CHANGED_BEACON_ENABLED) {
tasklet_disable(&dev->pre_tbtt_tasklet);
mt76x2_mac_set_beacon_enable(dev, mvif->idx,
info->enable_beacon);
mt76x02_mac_set_beacon_enable(dev, mvif->idx,
info->enable_beacon);
tasklet_enable(&dev->pre_tbtt_tasklet);
}
......
......@@ -36,7 +36,7 @@ mt76x2_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
if (!skb)
return;
mt76x2_mac_set_beacon(dev, mvif->idx, skb);
mt76x02_mac_set_beacon(dev, mvif->idx, skb);
}
static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment