summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/adm8211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-17 09:29:23 +0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-11 03:52:57 +0400
commit4150c57212ad134765dd78c654a4b9906252b66d (patch)
treec37ab7a3f75532a623ed00339782d769514422d2 /drivers/net/wireless/adm8211.c
parent070ac3a2651e3c1c4d277c5f1981517427c386a7 (diff)
downloadlinux-4150c57212ad134765dd78c654a4b9906252b66d.tar.xz
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor interfaces if they allow so-called "hard" monitor, and they are also supposed to keep track of multicast etc. This patch changes that, replaces the set_multicast_list() callback with a new configure_filter() callback that takes filter flags (FIF_*) instead of interface flags (IFF_*). For a driver, this means it should open the filter as much as necessary to get all frames requested by the filter flags. Accordingly, the filter flags are named "positively", e.g. FIF_ALLMULTI. Multicast filtering is a bit special in that drivers that have no multicast address filters need to allow multicast frames through when either the FIF_ALLMULTI flag is set or when the mc_count value is positive. At the same time, drivers are no longer notified about monitor interfaces at all, this means they now need to implement the start() and stop() callbacks and the new change_filter_flags() callback. Also, the start()/stop() ordering changed, start() is now called *before* any add_interface() as it really should be, and stop() after any remove_interface(). The patch also changes the behaviour of setting the bssid to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed and the filter flag FIF_BCN_PRBRESP_PROMISC introduced. This is a lot more efficient for hardware like b43 that supports it and other hardware can still set the BSSID to all-ones. Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu (rtl8187, adm8211, and p54), Larry Finger (b43legacy), and Ivo van Doorn (rt2x00). Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/adm8211.c')
-rw-r--r--drivers/net/wireless/adm8211.c144
1 files changed, 78 insertions, 66 deletions
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index ac2ea237019d..49a6b9eda4ea 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -281,49 +281,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev,
return 0;
}
-static void adm8211_set_rx_mode(struct ieee80211_hw *dev,
- unsigned short flags, int mc_count)
-{
- struct adm8211_priv *priv = dev->priv;
- unsigned int bit_nr;
- u32 mc_filter[2];
- struct dev_mc_list *mclist;
- void *tmp;
-
- if (flags & IFF_PROMISC) {
- priv->nar |= ADM8211_NAR_PR;
- priv->nar &= ~ADM8211_NAR_MM;
- mc_filter[1] = mc_filter[0] = ~0;
- } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
- priv->nar &= ~ADM8211_NAR_PR;
- priv->nar |= ADM8211_NAR_MM;
- mc_filter[1] = mc_filter[0] = ~0;
- } else {
- priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
- mc_filter[1] = mc_filter[0] = 0;
- mclist = NULL;
- while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
- bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
-
- bit_nr &= 0x3F;
- mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
- }
- }
-
- ADM8211_IDLE_RX();
-
- ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
- ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
- ADM8211_CSR_READ(NAR);
-
- if (flags & IFF_PROMISC)
- dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
- else
- dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
-
- ADM8211_RESTORE();
-}
-
static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
struct ieee80211_tx_queue_stats *stats)
{
@@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)
/* Clear the missed-packet counter. */
ADM8211_CSR_READ(LPC);
-
- if (!priv->mac_addr)
- return;
-
- /* set mac address */
- ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr);
- ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]);
}
static int adm8211_hw_reset(struct ieee80211_hw *dev)
@@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev,
ADM8211_CSR_WRITE(BPLI, reg);
}
-static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
+static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
{
struct adm8211_priv *priv = dev->priv;
u32 reg;
@@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
return 0;
}
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ priv->nar |= ADM8211_NAR_PR;
+ priv->nar &= ~ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ if (priv->nar & ADM8211_NAR_PR)
+ dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ else
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+
+ ADM8211_RESTORE();
+
+ *total_flags = new_flags;
+}
+
static int adm8211_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
- /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
- if (priv->mode != IEEE80211_IF_TYPE_MGMT)
- return -1;
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
switch (conf->type) {
case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_MNTR:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
- priv->mac_addr = conf->mac_addr;
+ ADM8211_IDLE();
+
+ ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr);
+ ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4));
+
+ adm8211_update_mode(dev);
+
+ ADM8211_RESTORE();
return 0;
}
@@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
}
static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev)
}
}
-static int adm8211_open(struct ieee80211_hw *dev)
+static int adm8211_start(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
int retval;
@@ -1550,7 +1563,7 @@ fail:
return retval;
}
-static int adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
@@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev)
free_irq(priv->pdev->irq, dev);
adm8211_free_rings(dev);
- return 0;
}
static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
@@ -1765,13 +1777,13 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev)
static const struct ieee80211_ops adm8211_ops = {
.tx = adm8211_tx,
- .open = adm8211_open,
+ .start = adm8211_start,
.stop = adm8211_stop,
.add_interface = adm8211_add_interface,
.remove_interface = adm8211_remove_interface,
.config = adm8211_config,
.config_interface = adm8211_config_interface,
- .set_multicast_list = adm8211_set_rx_mode,
+ .configure_filter = adm8211_configure_filter,
.get_stats = adm8211_get_stats,
.get_tx_stats = adm8211_get_tx_stats,
.get_tsf = adm8211_get_tsft
@@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
priv->tx_power = 0x40;
priv->lpf_cutoff = 0xFF;
priv->lnags_threshold = 0xFF;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
/* Power-on issue. EEPROM won't read correctly without */
if (priv->revid >= ADM8211_REV_BA) {
@@ -2000,7 +2012,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct adm8211_priv *priv = dev->priv;
- if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
ieee80211_stop_queues(dev);
adm8211_stop(dev);
}
@@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
- adm8211_open(dev);
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
+ adm8211_start(dev);
ieee80211_start_queues(dev);
}