2010-09-23 03:40:39

by greearb

[permalink] [raw]
Subject: [mac80211] ath5k: Support virtual interfaces.

From: Ben Greear <[email protected]>

This allows ath5k to support virtual STA and AP interfaces.

This patch is ported forward from a patch that Patrick McHardy
did for me against 2.6.31.

Signed-off-by: Ben Greear <[email protected]>
---
:100644 100644 504c6d6... 49f10ea... M drivers/net/wireless/ath/ath5k/base.c
:100644 100644 7f9d0d3... ec5c3c0... M drivers/net/wireless/ath/ath5k/base.h
:100644 100644 58912cd... 5b179d0... M drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/base.c | 249 +++++++++++++++++++++++++++-----
drivers/net/wireless/ath/ath5k/base.h | 27 +++-
drivers/net/wireless/ath/ath5k/reset.c | 4 +-
3 files changed, 236 insertions(+), 44 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 504c6d6..49f10ea 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -509,6 +509,29 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
}
}

+static void ath5k_update_bssid_mask(struct ath5k_softc *sc)
+{
+ struct ath5k_vif *avf;
+ unsigned int i, j;
+
+ /*
+ * This doesn't include the address of the default STA device in case
+ * it is reconfigured since for some reason it is not created through
+ * ->add_interface().
+ */
+ memset(sc->bssidmask, 0xff, ETH_ALEN);
+ for (i = 0; i < ATH5K_VIF_MAX; i++) {
+ if (sc->vifs[i] == NULL)
+ continue;
+ avf = (void *)sc->vifs[i]->drv_priv;
+ for (j = 0; j < ETH_ALEN; j++) {
+ sc->bssidmask[j] &= ~(sc->lladdr[j] ^ avf->lladdr[j]);
+ sc->bssidmask[j] &= ~(sc->lladdr[j] ^ avf->bssid[j]);
+ }
+ }
+ ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+}
+
static void
ath5k_mode_setup(struct ath5k_softc *sc)
{
@@ -520,7 +543,7 @@ ath5k_mode_setup(struct ath5k_softc *sc)
ath5k_hw_set_rx_filter(ah, rfilt);

if (ath5k_hw_hasbssidmask(ah))
- ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+ ath5k_update_bssid_mask(sc);

/* configure operational mode */
ath5k_hw_set_opmode(ah, sc->opmode);
@@ -694,13 +717,13 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
flags |= AR5K_TXDESC_RTSENA;
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
duration = le16_to_cpu(ieee80211_rts_duration(sc->hw,
- sc->vif, pktlen, info));
+ NULL, pktlen, info));
}
if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
flags |= AR5K_TXDESC_CTSENA;
cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
- sc->vif, pktlen, info));
+ NULL, pktlen, info));
}
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), padsize,
@@ -802,10 +825,13 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
list_add_tail(&bf->list, &sc->txbuf);
}

- /* beacon buffer */
- bf->desc = ds;
- bf->daddr = da;
- sc->bbuf = bf;
+ /* beacon buffers */
+ INIT_LIST_HEAD(&sc->bcbuf);
+ for (i = 0; i < ATH_BCBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+ bf->desc = ds;
+ bf->daddr = da;
+ list_add_tail(&bf->list, &sc->bcbuf);
+ }

return 0;
err_free:
@@ -820,11 +846,12 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
{
struct ath5k_buf *bf;

- ath5k_txbuf_free_skb(sc, sc->bbuf);
list_for_each_entry(bf, &sc->txbuf, list)
ath5k_txbuf_free_skb(sc, bf);
list_for_each_entry(bf, &sc->rxbuf, list)
ath5k_rxbuf_free_skb(sc, bf);
+ list_for_each_entry(bf, &sc->bcbuf, list)
+ ath5k_txbuf_free_skb(sc, bf);

/* Free memory associated with all descriptors */
pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
@@ -833,7 +860,6 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)

kfree(sc->bufptr);
sc->bufptr = NULL;
- sc->bbuf = NULL;
}


@@ -1737,6 +1763,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
int ret;
struct ath5k_softc *sc = hw->priv;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
struct sk_buff *skb;

if (WARN_ON(!vif)) {
@@ -1753,11 +1780,34 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)

ath5k_debug_dump_skb(sc, skb, "BC ", 1);

- ath5k_txbuf_free_skb(sc, sc->bbuf);
- sc->bbuf->skb = skb;
- ret = ath5k_beacon_setup(sc, sc->bbuf);
+ if (!avf->bbuf) {
+ WARN_ON(list_empty(&sc->bcbuf));
+ avf->bbuf = list_first_entry(&sc->bcbuf, struct ath5k_buf,
+ list);
+ list_del(&avf->bbuf->list);
+
+ /* Assign the vap to a beacon xmit slot. */
+ if (avf->opmode == NL80211_IFTYPE_AP) {
+ int slot;
+
+ avf->bslot = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->bslot[slot] == ATH5K_IF_ID_ANY) {
+ avf->bslot = slot;
+ break;
+ }
+ }
+ BUG_ON(sc->bslot[avf->bslot] != ATH5K_IF_ID_ANY);
+ sc->bslot[avf->bslot] = avf->if_id;
+ sc->nbcnvifs++;
+ }
+ }
+
+ ath5k_txbuf_free_skb(sc, avf->bbuf);
+ avf->bbuf->skb = skb;
+ ret = ath5k_beacon_setup(sc, avf->bbuf);
if (ret)
- sc->bbuf->skb = NULL;
+ avf->bbuf->skb = NULL;
out:
return ret;
}
@@ -1773,16 +1823,18 @@ out:
static void
ath5k_beacon_send(struct ath5k_softc *sc)
{
- struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct ieee80211_vif *vif;
+ struct ath5k_vif *avf;
+ struct ath5k_buf *bf;
struct sk_buff *skb;
+ u64 tsf;
+ u32 tsftu;
+ u16 intval;
+ int slot, if_id;

ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");

- if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION)) {
- ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
- return;
- }
/*
* Check if the previous beacon has gone out. If
* not, don't don't try to post another: skip this
@@ -1811,6 +1863,29 @@ ath5k_beacon_send(struct ath5k_softc *sc)
sc->bmisscount = 0;
}

+ intval = sc->bintval ? sc->bintval : ATH5K_DEFAULT_BINTVAL;
+
+ tsf = ath5k_hw_get_tsf64(ah);
+ tsftu = TSF_TO_TU(tsf);
+ slot = ((tsftu % intval) * ATH_BCBUF) / intval;
+ if_id = sc->bslot[(slot + 1) % ATH_BCBUF];
+
+ pr_debug("tsf %llx tsftu %x intval %u slot %u if_id %x\n",
+ (unsigned long long)tsf, tsftu, intval, slot, if_id);
+
+ if (if_id != ATH5K_IF_ID_ANY) {
+ vif = sc->vifs[if_id];
+ avf = (void *)vif->drv_priv;
+ } else
+ return;
+
+ bf = avf->bbuf;
+ if (unlikely(bf->skb == NULL || sc->opmode == NL80211_IFTYPE_STATION ||
+ sc->opmode == NL80211_IFTYPE_MONITOR)) {
+ ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+ return;
+ }
+
/*
* Stop any current dma and put the new frame on the queue.
* This should never fail since we check above that no frames
@@ -1823,17 +1898,17 @@ ath5k_beacon_send(struct ath5k_softc *sc)

/* refresh the beacon for AP mode */
if (sc->opmode == NL80211_IFTYPE_AP)
- ath5k_beacon_update(sc->hw, sc->vif);
+ ath5k_beacon_update(sc->hw, vif);

ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
ath5k_hw_start_tx_dma(ah, sc->bhalq);
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);

- skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
while (skb) {
ath5k_tx_queue(sc->hw, skb, sc->cabq);
- skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ skb = ieee80211_get_buffered_bc(sc->hw, vif);
}

sc->bsent++;
@@ -1863,6 +1938,12 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
u64 hw_tsf;

intval = sc->bintval & AR5K_BEACON_PERIOD;
+ if (sc->opmode == NL80211_IFTYPE_AP) {
+ intval /= ATH_BCBUF; /* staggered multi-bss beacons */
+ if (intval < 15)
+ ATH5K_WARN(sc, "intval %u is too low, min 15\n",
+ intval);
+ }
if (WARN_ON(!intval))
return;

@@ -2052,6 +2133,15 @@ ath5k_intr(int irq, void *dev_id)

do {
ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */
+ {
+ static unsigned int irq_counter;
+ if ((++irq_counter % 10000) == 9999) {
+ ATH5K_WARN(sc, "status 0x%x/0x%x dev_id: %p"
+ " counter: %i irq_counter: %i\n",
+ status, sc->imask, dev_id, counter,
+ irq_counter);
+ }
+ }
ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
status, sc->imask);
if (unlikely(status & AR5K_INT_FATAL)) {
@@ -2307,6 +2397,10 @@ ath5k_init(struct ath5k_softc *sc)
ath_hw_keyreset(common, (u16) i);

ath5k_hw_set_ack_bitrate_high(ah, true);
+
+ for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
+ sc->bslot[i] = ATH5K_IF_ID_ANY;
+
ret = 0;
done:
mmiowb();
@@ -2366,7 +2460,6 @@ ath5k_stop_hw(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
"putting device to sleep\n");
}
- ath5k_txbuf_free_skb(sc, sc->bbuf);

mmiowb();
mutex_unlock(&sc->lock);
@@ -2571,9 +2664,9 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
}

SET_IEEE80211_PERM_ADDR(hw, mac);
+ memcpy(&sc->lladdr, mac, ETH_ALEN);
/* All MAC address bits matter for ACKs */
- memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
- ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+ ath5k_update_bssid_mask(sc);

regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
@@ -2671,30 +2764,70 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
int ret;
+ struct ath5k_hw *ah = sc->ah;
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
+ unsigned int i;

mutex_lock(&sc->lock);
- if (sc->vif) {
- ret = 0;
+
+ if (sc->nvifs > 1 && !modparam_nohwcrypt) {
+ pr_err("ath5k: can not add multiple virtual interfaces with hardware encryption\n");
+ ret = -EOPNOTSUPP;
goto end;
}

- sc->vif = vif;
+ if (sc->nvifs >= ATH5K_VIF_MAX ||
+ (vif->type == NL80211_IFTYPE_AP && sc->nbcnvifs >= ATH_BCBUF)) {
+ ret = -ELNRNG;
+ goto end;
+ }
+ for (i = 0; i < ATH5K_VIF_MAX; i++) {
+ if (sc->vifs[i] != NULL)
+ continue;
+ sc->vifs[i] = vif;
+ avf->if_id = i;
+ break;
+ }
+ sc->nvifs++;

switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
- sc->opmode = vif->type;
+ avf->opmode = vif->type;
break;
default:
ret = -EOPNOTSUPP;
goto end;
}

- ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode);
+ ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", avf->opmode);

+ /* Set combined mode - when APs are configured, operate in AP mode.
+ * Otherwise use the mode of the new interface. This can currently
+ * only deal with combinations of APs and STAs I think ...
+ */
+ if (sc->nbcnvifs)
+ sc->opmode = NL80211_IFTYPE_AP;
+ else
+ sc->opmode = vif->type;
+
+ ath5k_hw_set_opmode(ah, sc->opmode);
+
+ /* Set to a reasonable value. Note that this will
+ * be set to mac80211's value at ath5k_config(). */
+ sc->bintval = ATH5K_DEFAULT_BINTVAL;
+
+ /* Any MAC address is finee, all others are included through the
+ * filter.
+ */
+ memcpy(&sc->lladdr, vif->addr, ETH_ALEN);
ath5k_hw_set_lladdr(sc->ah, vif->addr);
+
+ memcpy(&avf->lladdr, vif->addr, ETH_ALEN);
+ memcpy(&avf->bssid, vif->addr, ETH_ALEN);
+
ath5k_mode_setup(sc);

ret = 0;
@@ -2708,15 +2841,32 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath5k_softc *sc = hw->priv;
- u8 mac[ETH_ALEN] = {};
+ struct ath5k_vif *avf = (void *)vif->drv_priv, *avf2;
+ u8 null_mac[ETH_ALEN] = {}, *mac = null_mac;
+ unsigned int i;

mutex_lock(&sc->lock);
- if (sc->vif != vif)
- goto end;
+ sc->vifs[avf->if_id] = NULL;
+ sc->nvifs--;
+
+ for (i = 0; i < ATH5K_VIF_MAX; i++) {
+ if (sc->vifs[i] == NULL)
+ continue;
+ avf2 = (void *)sc->vifs[i]->drv_priv;
+ mac = avf2->lladdr;
+ break;
+ }
+
+ if (avf->bbuf) {
+ ath5k_txbuf_free_skb(sc, avf->bbuf);
+ list_add_tail(&avf->bbuf->list, &sc->bcbuf);
+ sc->bslot[avf->bslot] = ATH5K_IF_ID_ANY;
+ sc->nbcnvifs--;
+ avf->bbuf = NULL;
+ }

ath5k_hw_set_lladdr(sc->ah, mac);
- sc->vif = NULL;
-end:
+ ath5k_update_bssid_mask(sc);
mutex_unlock(&sc->lock);
}

@@ -2799,6 +2949,23 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
return ((u64)(mfilt[1]) << 32) | mfilt[0];
}

+static bool ath_any_vif_assoc(struct ath5k_softc *sc)
+{
+ int i;
+ int seen = 0;
+ for (i = 0; i < ATH5K_VIF_MAX; i++) {
+ if (sc->vifs[i]) {
+ struct ath5k_vif *avf = (void *)sc->vifs[i]->drv_priv;
+ seen++;
+ if (avf->assoc)
+ return true;
+ if (seen >= sc->nvifs)
+ break;
+ }
+ }
+ return false;
+}
+
#define SUPPORTED_FIF_FLAGS \
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2869,7 +3036,7 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,

/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
* and probes for any BSSID */
- if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+ if ((*new_flags & FIF_BCN_PRBRESP_PROMISC) || (sc->nvifs > 1))
rfilt |= AR5K_RX_FILTER_BEACON;

/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
@@ -3054,13 +3221,14 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u32 changes)
{
+ struct ath5k_vif *avf = (void *)vif->drv_priv;
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
struct ath_common *common = ath5k_hw_common(ah);
unsigned long flags;

mutex_lock(&sc->lock);
- if (WARN_ON(sc->vif != vif))
+ if (WARN_ON(sc->vifs[avf->if_id] != vif))
goto unlock;

if (changes & BSS_CHANGED_BSSID) {
@@ -3075,7 +3243,12 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->bintval = bss_conf->beacon_int;

if (changes & BSS_CHANGED_ASSOC) {
- sc->assoc = bss_conf->assoc;
+ avf->assoc = bss_conf->assoc;
+ if (bss_conf->assoc)
+ sc->assoc = bss_conf->assoc;
+ else
+ sc->assoc = ath_any_vif_assoc(sc);
+
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
@@ -3378,6 +3551,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
hw->max_rate_tries = 11;
}

+ hw->vif_data_size = sizeof(struct ath5k_vif);
+
/* Finish private driver data initialization */
ret = ath5k_attach(pdev, hw);
if (ret)
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 7f9d0d3..ec5c3c0 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -58,8 +58,8 @@

#define ATH_RXBUF 40 /* number of RX buffers */
#define ATH_TXBUF 200 /* number of TX buffers */
-#define ATH_BCBUF 1 /* number of beacon buffers */
-
+#define ATH_BCBUF 16 /* number of beacon buffers */
+#define ATH5K_DEFAULT_BINTVAL 1000
#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */
#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */

@@ -152,6 +152,19 @@ struct ath5k_statistics {
#define ATH_CHAN_MAX (14+14+14+252+20)
#endif

+#define ATH5K_VIF_MAX 2048
+#define ATH5K_IF_ID_ANY -1
+
+struct ath5k_vif {
+ bool assoc; /* are we associated or not */
+ int if_id;
+ enum nl80211_iftype opmode;
+ int bslot;
+ struct ath5k_buf *bbuf; /* beacon buffer */
+ u8 lladdr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+};
+
/* Software Carrier, keeps track of the driver state
* associated with an instance of a device */
struct ath5k_softc {
@@ -188,10 +201,12 @@ struct ath5k_softc {
unsigned int curmode; /* current phy mode */
struct ieee80211_channel *curchan; /* current h/w channel */

- struct ieee80211_vif *vif;
+ u16 nvifs;
+ struct ieee80211_vif *vifs[ATH5K_VIF_MAX];

enum ath5k_int imask; /* interrupt mask copy */

+ u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN];

unsigned int led_pin, /* GPIO pin for driving LED */
@@ -219,7 +234,9 @@ struct ath5k_softc {

spinlock_t block; /* protects beacon */
struct tasklet_struct beacontq; /* beacon intr tasklet */
- struct ath5k_buf *bbuf; /* beacon buffer */
+ struct list_head bcbuf; /* beacon buffer */
+ int bslot[ATH_BCBUF];
+ u16 nbcnvifs;
unsigned int bhalq, /* SW q for outgoing beacons */
bmisscount, /* missed beacon transmits */
bintval, /* beacon interval in TU */
@@ -228,7 +245,7 @@ struct ath5k_softc {
struct ath5k_txq *cabq; /* content after beacon */

int power_level; /* Requested tx power in dbm */
- bool assoc; /* associate state */
+ bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */

struct ath5k_statistics stats;
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 58912cd..5b179d0 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -167,7 +167,7 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
* ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */
tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
- sc->vif, 10, rate));
+ NULL, 10, rate));

ath5k_hw_reg_write(ah, tx_time, reg);

@@ -1060,7 +1060,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
* XXX: rethink this after new mode changes to
* mac80211 are integrated */
if (ah->ah_version == AR5K_AR5212 &&
- ah->ah_sc->vif != NULL)
+ ah->ah_sc->nvifs)
ath5k_hw_write_rate_duration(ah, mode);

/*
--
1.7.2.3



2010-09-23 09:56:26

by Felix Fietkau

[permalink] [raw]
Subject: Re: [mac80211] ath5k: Support virtual interfaces.

On 2010-09-23 5:40 AM, [email protected] wrote:
> From: Ben Greear <[email protected]>
>
> This allows ath5k to support virtual STA and AP interfaces.
>
> This patch is ported forward from a patch that Patrick McHardy
> did for me against 2.6.31.
>
> Signed-off-by: Ben Greear <[email protected]>
> ---
> :100644 100644 504c6d6... 49f10ea... M drivers/net/wireless/ath/ath5k/base.c
> :100644 100644 7f9d0d3... ec5c3c0... M drivers/net/wireless/ath/ath5k/base.h
> :100644 100644 58912cd... 5b179d0... M drivers/net/wireless/ath/ath5k/reset.c
> drivers/net/wireless/ath/ath5k/base.c | 249 +++++++++++++++++++++++++++-----
> drivers/net/wireless/ath/ath5k/base.h | 27 +++-
> drivers/net/wireless/ath/ath5k/reset.c | 4 +-
> 3 files changed, 236 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
> index 504c6d6..49f10ea 100644
> --- a/drivers/net/wireless/ath/ath5k/base.c
> +++ b/drivers/net/wireless/ath/ath5k/base.c
> @@ -509,6 +509,29 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
> }
> }
>
> +static void ath5k_update_bssid_mask(struct ath5k_softc *sc)
> +{
> + struct ath5k_vif *avf;
> + unsigned int i, j;
> +
> + /*
> + * This doesn't include the address of the default STA device in case
> + * it is reconfigured since for some reason it is not created through
> + * ->add_interface().
> + */
> + memset(sc->bssidmask, 0xff, ETH_ALEN);
> + for (i = 0; i < ATH5K_VIF_MAX; i++) {
> + if (sc->vifs[i] == NULL)
> + continue;
> + avf = (void *)sc->vifs[i]->drv_priv;
> + for (j = 0; j < ETH_ALEN; j++) {
> + sc->bssidmask[j] &= ~(sc->lladdr[j] ^ avf->lladdr[j]);
> + sc->bssidmask[j] &= ~(sc->lladdr[j] ^ avf->bssid[j]);
avf->bssid seems to be duplicated. I think you can remove that field
entirely. And even if it were to contain the BSSID (in the STA case),
you should not use it to calculate the bssidmask.


> @@ -2671,30 +2764,70 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
> {
> struct ath5k_softc *sc = hw->priv;
> int ret;
> + struct ath5k_hw *ah = sc->ah;
> + struct ath5k_vif *avf = (void *)vif->drv_priv;
> + unsigned int i;
>
> mutex_lock(&sc->lock);
> - if (sc->vif) {
> - ret = 0;
> +
> + if (sc->nvifs > 1 && !modparam_nohwcrypt) {
> + pr_err("ath5k: can not add multiple virtual interfaces with hardware encryption\n");
Why not? Other drivers can do this just fine.

> diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
> index 7f9d0d3..ec5c3c0 100644
> --- a/drivers/net/wireless/ath/ath5k/base.h
> +++ b/drivers/net/wireless/ath/ath5k/base.h
> @@ -58,8 +58,8 @@
>
> #define ATH_RXBUF 40 /* number of RX buffers */
> #define ATH_TXBUF 200 /* number of TX buffers */
> -#define ATH_BCBUF 1 /* number of beacon buffers */
> -
> +#define ATH_BCBUF 16 /* number of beacon buffers */
A value of 16 here seems a bit much for staggered beacons. IMHO that
will increase the likelihood of stuck beacon issues in the long run.
I think 4 would be a better value to start with for now.
In the future we should probably make the SWBA timing more dynamic based
on the actual number of AP mode interfaces.

- Felix

2010-09-23 13:26:10

by Felix Fietkau

[permalink] [raw]
Subject: Re: [mac80211] ath5k: Support virtual interfaces.

On 2010-09-23 3:09 PM, Ben Greear wrote:
> On 09/23/2010 02:56 AM, Felix Fietkau wrote:
>> On 2010-09-23 5:40 AM, [email protected] wrote:
>>> From: Ben Greear<[email protected]>
>>>
>>> This allows ath5k to support virtual STA and AP interfaces.
>>>
>>> This patch is ported forward from a patch that Patrick McHardy
>>> did for me against 2.6.31.
>>>
>>> Signed-off-by: Ben Greear<[email protected]>
>>> ---
>>> :100644 100644 504c6d6... 49f10ea... M drivers/net/wireless/ath/ath5k/base.c
>>> :100644 100644 7f9d0d3... ec5c3c0... M drivers/net/wireless/ath/ath5k/base.h
>>> :100644 100644 58912cd... 5b179d0... M drivers/net/wireless/ath/ath5k/reset.c
>>> drivers/net/wireless/ath/ath5k/base.c | 249 +++++++++++++++++++++++++++-----
>>> drivers/net/wireless/ath/ath5k/base.h | 27 +++-
>>> drivers/net/wireless/ath/ath5k/reset.c | 4 +-
>>> 3 files changed, 236 insertions(+), 44 deletions(-)
>>>
>>> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
>>> index 504c6d6..49f10ea 100644
>>> --- a/drivers/net/wireless/ath/ath5k/base.c
>>> +++ b/drivers/net/wireless/ath/ath5k/base.c
>>> @@ -509,6 +509,29 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
>>> }
>>> }
>>>
>>> +static void ath5k_update_bssid_mask(struct ath5k_softc *sc)
>>> +{
>>> + struct ath5k_vif *avf;
>>> + unsigned int i, j;
>>> +
>>> + /*
>>> + * This doesn't include the address of the default STA device in case
>>> + * it is reconfigured since for some reason it is not created through
>>> + * ->add_interface().
>>> + */
>>> + memset(sc->bssidmask, 0xff, ETH_ALEN);
>>> + for (i = 0; i< ATH5K_VIF_MAX; i++) {
>>> + if (sc->vifs[i] == NULL)
>>> + continue;
>>> + avf = (void *)sc->vifs[i]->drv_priv;
>>> + for (j = 0; j< ETH_ALEN; j++) {
>>> + sc->bssidmask[j]&= ~(sc->lladdr[j] ^ avf->lladdr[j]);
>>> + sc->bssidmask[j]&= ~(sc->lladdr[j] ^ avf->bssid[j]);
>> avf->bssid seems to be duplicated. I think you can remove that field
>> entirely. And even if it were to contain the BSSID (in the STA case),
>> you should not use it to calculate the bssidmask.
>
> I'll check on this.. Might could make it more like ath9k's anyway.
>
>>
>>
>>> @@ -2671,30 +2764,70 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
>>> {
>>> struct ath5k_softc *sc = hw->priv;
>>> int ret;
>>> + struct ath5k_hw *ah = sc->ah;
>>> + struct ath5k_vif *avf = (void *)vif->drv_priv;
>>> + unsigned int i;
>>>
>>> mutex_lock(&sc->lock);
>>> - if (sc->vif) {
>>> - ret = 0;
>>> +
>>> + if (sc->nvifs> 1&& !modparam_nohwcrypt) {
>>> + pr_err("ath5k: can not add multiple virtual interfaces with hardware encryption\n");
>> Why not? Other drivers can do this just fine.
>
> ath9k and ath5k, at least, cannot do multiple STA with hardware encryption,
> as far as I know.
I think that can be fixed in software by switching over to using address
based key lookup. In either case, this should not restrict the use of
multiple AP interfaces...

>>> diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
>>> index 7f9d0d3..ec5c3c0 100644
>>> --- a/drivers/net/wireless/ath/ath5k/base.h
>>> +++ b/drivers/net/wireless/ath/ath5k/base.h
>>> @@ -58,8 +58,8 @@
>>>
>>> #define ATH_RXBUF 40 /* number of RX buffers */
>>> #define ATH_TXBUF 200 /* number of TX buffers */
>>> -#define ATH_BCBUF 1 /* number of beacon buffers */
>>> -
>>> +#define ATH_BCBUF 16 /* number of beacon buffers */
>> A value of 16 here seems a bit much for staggered beacons. IMHO that
>> will increase the likelihood of stuck beacon issues in the long run.
>> I think 4 would be a better value to start with for now.
>> In the future we should probably make the SWBA timing more dynamic based
>> on the actual number of AP mode interfaces.
>
> We ran tests before with at least 8 VAPs and it seemed to work fine. Maybe
> we can compromise to 8?
Did you test it under very heavy load? My suggestion for supporting more
interfaces would be to keep 4 SWBA slots, and after the fourth interface
is added, assign the extra interfaces to the existing slots.
Then when transmitting beacons, link together all DMA descriptors
assigned to the current slot. That way you have less issues with
imprecise timers, IRQ delays and similar things, which are more likely
to show up on embedded hardware than on regular PCs. This also has the
advantage of using less power, as it generates less useless wakeups per
second.

- Felix


2010-09-23 13:09:26

by Ben Greear

[permalink] [raw]
Subject: Re: [mac80211] ath5k: Support virtual interfaces.

On 09/23/2010 02:56 AM, Felix Fietkau wrote:
> On 2010-09-23 5:40 AM, [email protected] wrote:
>> From: Ben Greear<[email protected]>
>>
>> This allows ath5k to support virtual STA and AP interfaces.
>>
>> This patch is ported forward from a patch that Patrick McHardy
>> did for me against 2.6.31.
>>
>> Signed-off-by: Ben Greear<[email protected]>
>> ---
>> :100644 100644 504c6d6... 49f10ea... M drivers/net/wireless/ath/ath5k/base.c
>> :100644 100644 7f9d0d3... ec5c3c0... M drivers/net/wireless/ath/ath5k/base.h
>> :100644 100644 58912cd... 5b179d0... M drivers/net/wireless/ath/ath5k/reset.c
>> drivers/net/wireless/ath/ath5k/base.c | 249 +++++++++++++++++++++++++++-----
>> drivers/net/wireless/ath/ath5k/base.h | 27 +++-
>> drivers/net/wireless/ath/ath5k/reset.c | 4 +-
>> 3 files changed, 236 insertions(+), 44 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
>> index 504c6d6..49f10ea 100644
>> --- a/drivers/net/wireless/ath/ath5k/base.c
>> +++ b/drivers/net/wireless/ath/ath5k/base.c
>> @@ -509,6 +509,29 @@ ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
>> }
>> }
>>
>> +static void ath5k_update_bssid_mask(struct ath5k_softc *sc)
>> +{
>> + struct ath5k_vif *avf;
>> + unsigned int i, j;
>> +
>> + /*
>> + * This doesn't include the address of the default STA device in case
>> + * it is reconfigured since for some reason it is not created through
>> + * ->add_interface().
>> + */
>> + memset(sc->bssidmask, 0xff, ETH_ALEN);
>> + for (i = 0; i< ATH5K_VIF_MAX; i++) {
>> + if (sc->vifs[i] == NULL)
>> + continue;
>> + avf = (void *)sc->vifs[i]->drv_priv;
>> + for (j = 0; j< ETH_ALEN; j++) {
>> + sc->bssidmask[j]&= ~(sc->lladdr[j] ^ avf->lladdr[j]);
>> + sc->bssidmask[j]&= ~(sc->lladdr[j] ^ avf->bssid[j]);
> avf->bssid seems to be duplicated. I think you can remove that field
> entirely. And even if it were to contain the BSSID (in the STA case),
> you should not use it to calculate the bssidmask.

I'll check on this.. Might could make it more like ath9k's anyway.

>
>
>> @@ -2671,30 +2764,70 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
>> {
>> struct ath5k_softc *sc = hw->priv;
>> int ret;
>> + struct ath5k_hw *ah = sc->ah;
>> + struct ath5k_vif *avf = (void *)vif->drv_priv;
>> + unsigned int i;
>>
>> mutex_lock(&sc->lock);
>> - if (sc->vif) {
>> - ret = 0;
>> +
>> + if (sc->nvifs> 1&& !modparam_nohwcrypt) {
>> + pr_err("ath5k: can not add multiple virtual interfaces with hardware encryption\n");
> Why not? Other drivers can do this just fine.

ath9k and ath5k, at least, cannot do multiple STA with hardware encryption,
as far as I know.

This just keeps the user from doing something that cannot work.

>
>> diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
>> index 7f9d0d3..ec5c3c0 100644
>> --- a/drivers/net/wireless/ath/ath5k/base.h
>> +++ b/drivers/net/wireless/ath/ath5k/base.h
>> @@ -58,8 +58,8 @@
>>
>> #define ATH_RXBUF 40 /* number of RX buffers */
>> #define ATH_TXBUF 200 /* number of TX buffers */
>> -#define ATH_BCBUF 1 /* number of beacon buffers */
>> -
>> +#define ATH_BCBUF 16 /* number of beacon buffers */
> A value of 16 here seems a bit much for staggered beacons. IMHO that
> will increase the likelihood of stuck beacon issues in the long run.
> I think 4 would be a better value to start with for now.
> In the future we should probably make the SWBA timing more dynamic based
> on the actual number of AP mode interfaces.

We ran tests before with at least 8 VAPs and it seemed to work fine. Maybe
we can compromise to 8?

Thanks,
Ben

>
> - Felix


--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com

2010-09-23 13:31:28

by Ben Greear

[permalink] [raw]
Subject: Re: [mac80211] ath5k: Support virtual interfaces.

On 09/23/2010 06:25 AM, Felix Fietkau wrote:
> On 2010-09-23 3:09 PM, Ben Greear wrote:

>>>> + if (sc->nvifs> 1&& !modparam_nohwcrypt) {
>>>> + pr_err("ath5k: can not add multiple virtual interfaces with hardware encryption\n");
>>> Why not? Other drivers can do this just fine.
>>
>> ath9k and ath5k, at least, cannot do multiple STA with hardware encryption,
>> as far as I know.
> I think that can be fixed in software by switching over to using address
> based key lookup. In either case, this should not restrict the use of
> multiple AP interfaces...

Ok, I'll remove that code.

>
>>>> diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
>>>> index 7f9d0d3..ec5c3c0 100644
>>>> --- a/drivers/net/wireless/ath/ath5k/base.h
>>>> +++ b/drivers/net/wireless/ath/ath5k/base.h
>>>> @@ -58,8 +58,8 @@
>>>>
>>>> #define ATH_RXBUF 40 /* number of RX buffers */
>>>> #define ATH_TXBUF 200 /* number of TX buffers */
>>>> -#define ATH_BCBUF 1 /* number of beacon buffers */
>>>> -
>>>> +#define ATH_BCBUF 16 /* number of beacon buffers */
>>> A value of 16 here seems a bit much for staggered beacons. IMHO that
>>> will increase the likelihood of stuck beacon issues in the long run.
>>> I think 4 would be a better value to start with for now.
>>> In the future we should probably make the SWBA timing more dynamic based
>>> on the actual number of AP mode interfaces.
>>
>> We ran tests before with at least 8 VAPs and it seemed to work fine. Maybe
>> we can compromise to 8?
> Did you test it under very heavy load? My suggestion for supporting more
> interfaces would be to keep 4 SWBA slots, and after the fourth interface
> is added, assign the extra interfaces to the existing slots.
> Then when transmitting beacons, link together all DMA descriptors
> assigned to the current slot. That way you have less issues with
> imprecise timers, IRQ delays and similar things, which are more likely
> to show up on embedded hardware than on regular PCs. This also has the
> advantage of using less power, as it generates less useless wakeups per
> second.

We did test under load. But, the truth is, I don't really understand this
beacon code..it was not originally written by me. Also, I haven't tested
APs yet in .36...just STA so far.

If you think it should be limited to 4, I'll go ahead and do that.

Someone that understands it better can increase it later if desired.

Thanks,
Ben

>
> - Felix


--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com