aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/adm8211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-17 01:29:23 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:57 -0400
commit4150c57212ad134765dd78c654a4b9906252b66d (patch)
treec37ab7a3f75532a623ed00339782d769514422d2 /drivers/net/wireless/adm8211.c
parent070ac3a2651e3c1c4d277c5f1981517427c386a7 (diff)
[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,
281 return 0; 281 return 0;
282} 282}
283 283
284static void adm8211_set_rx_mode(struct ieee80211_hw *dev,
285 unsigned short flags, int mc_count)
286{
287 struct adm8211_priv *priv = dev->priv;
288 unsigned int bit_nr;
289 u32 mc_filter[2];
290 struct dev_mc_list *mclist;
291 void *tmp;
292
293 if (flags & IFF_PROMISC) {
294 priv->nar |= ADM8211_NAR_PR;
295 priv->nar &= ~ADM8211_NAR_MM;
296 mc_filter[1] = mc_filter[0] = ~0;
297 } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
298 priv->nar &= ~ADM8211_NAR_PR;
299 priv->nar |= ADM8211_NAR_MM;
300 mc_filter[1] = mc_filter[0] = ~0;
301 } else {
302 priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
303 mc_filter[1] = mc_filter[0] = 0;
304 mclist = NULL;
305 while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
306 bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
307
308 bit_nr &= 0x3F;
309 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
310 }
311 }
312
313 ADM8211_IDLE_RX();
314
315 ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
316 ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
317 ADM8211_CSR_READ(NAR);
318
319 if (flags & IFF_PROMISC)
320 dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
321 else
322 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
323
324 ADM8211_RESTORE();
325}
326
327static int adm8211_get_tx_stats(struct ieee80211_hw *dev, 284static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
328 struct ieee80211_tx_queue_stats *stats) 285 struct ieee80211_tx_queue_stats *stats)
329{ 286{
@@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)
1254 1211
1255 /* Clear the missed-packet counter. */ 1212 /* Clear the missed-packet counter. */
1256 ADM8211_CSR_READ(LPC); 1213 ADM8211_CSR_READ(LPC);
1257
1258 if (!priv->mac_addr)
1259 return;
1260
1261 /* set mac address */
1262 ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr);
1263 ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]);
1264} 1214}
1265 1215
1266static int adm8211_hw_reset(struct ieee80211_hw *dev) 1216static int adm8211_hw_reset(struct ieee80211_hw *dev)
@@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev,
1334 ADM8211_CSR_WRITE(BPLI, reg); 1284 ADM8211_CSR_WRITE(BPLI, reg);
1335} 1285}
1336 1286
1337static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) 1287static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
1338{ 1288{
1339 struct adm8211_priv *priv = dev->priv; 1289 struct adm8211_priv *priv = dev->priv;
1340 u32 reg; 1290 u32 reg;
@@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
1395 return 0; 1345 return 0;
1396} 1346}
1397 1347
1348static void adm8211_configure_filter(struct ieee80211_hw *dev,
1349 unsigned int changed_flags,
1350 unsigned int *total_flags,
1351 int mc_count, struct dev_mc_list *mclist)
1352{
1353 static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1354 struct adm8211_priv *priv = dev->priv;
1355 unsigned int bit_nr, new_flags;
1356 u32 mc_filter[2];
1357 int i;
1358
1359 new_flags = 0;
1360
1361 if (*total_flags & FIF_PROMISC_IN_BSS) {
1362 new_flags |= FIF_PROMISC_IN_BSS;
1363 priv->nar |= ADM8211_NAR_PR;
1364 priv->nar &= ~ADM8211_NAR_MM;
1365 mc_filter[1] = mc_filter[0] = ~0;
1366 } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
1367 new_flags |= FIF_ALLMULTI;
1368 priv->nar &= ~ADM8211_NAR_PR;
1369 priv->nar |= ADM8211_NAR_MM;
1370 mc_filter[1] = mc_filter[0] = ~0;
1371 } else {
1372 priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
1373 mc_filter[1] = mc_filter[0] = 0;
1374 for (i = 0; i < mc_count; i++) {
1375 if (!mclist)
1376 break;
1377 bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
1378
1379 bit_nr &= 0x3F;
1380 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
1381 mclist = mclist->next;
1382 }
1383 }
1384
1385 ADM8211_IDLE_RX();
1386
1387 ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
1388 ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
1389 ADM8211_CSR_READ(NAR);
1390
1391 if (priv->nar & ADM8211_NAR_PR)
1392 dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
1393 else
1394 dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
1395
1396 if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
1397 adm8211_set_bssid(dev, bcast);
1398 else
1399 adm8211_set_bssid(dev, priv->bssid);
1400
1401 ADM8211_RESTORE();
1402
1403 *total_flags = new_flags;
1404}
1405
1398static int adm8211_add_interface(struct ieee80211_hw *dev, 1406static int adm8211_add_interface(struct ieee80211_hw *dev,
1399 struct ieee80211_if_init_conf *conf) 1407 struct ieee80211_if_init_conf *conf)
1400{ 1408{
1401 struct adm8211_priv *priv = dev->priv; 1409 struct adm8211_priv *priv = dev->priv;
1402 /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ 1410 if (priv->mode != IEEE80211_IF_TYPE_MNTR)
1403 if (priv->mode != IEEE80211_IF_TYPE_MGMT) 1411 return -EOPNOTSUPP;
1404 return -1;
1405 1412
1406 switch (conf->type) { 1413 switch (conf->type) {
1407 case IEEE80211_IF_TYPE_STA: 1414 case IEEE80211_IF_TYPE_STA:
1408 case IEEE80211_IF_TYPE_MNTR:
1409 priv->mode = conf->type; 1415 priv->mode = conf->type;
1410 break; 1416 break;
1411 default: 1417 default:
1412 return -EOPNOTSUPP; 1418 return -EOPNOTSUPP;
1413 } 1419 }
1414 1420
1415 priv->mac_addr = conf->mac_addr; 1421 ADM8211_IDLE();
1422
1423 ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr);
1424 ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4));
1425
1426 adm8211_update_mode(dev);
1427
1428 ADM8211_RESTORE();
1416 1429
1417 return 0; 1430 return 0;
1418} 1431}
@@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev,
1421 struct ieee80211_if_init_conf *conf) 1434 struct ieee80211_if_init_conf *conf)
1422{ 1435{
1423 struct adm8211_priv *priv = dev->priv; 1436 struct adm8211_priv *priv = dev->priv;
1424 priv->mode = IEEE80211_IF_TYPE_MGMT; 1437 priv->mode = IEEE80211_IF_TYPE_MNTR;
1425} 1438}
1426 1439
1427static int adm8211_init_rings(struct ieee80211_hw *dev) 1440static int adm8211_init_rings(struct ieee80211_hw *dev)
@@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev)
1505 } 1518 }
1506} 1519}
1507 1520
1508static int adm8211_open(struct ieee80211_hw *dev) 1521static int adm8211_start(struct ieee80211_hw *dev)
1509{ 1522{
1510 struct adm8211_priv *priv = dev->priv; 1523 struct adm8211_priv *priv = dev->priv;
1511 int retval; 1524 int retval;
@@ -1550,7 +1563,7 @@ fail:
1550 return retval; 1563 return retval;
1551} 1564}
1552 1565
1553static int adm8211_stop(struct ieee80211_hw *dev) 1566static void adm8211_stop(struct ieee80211_hw *dev)
1554{ 1567{
1555 struct adm8211_priv *priv = dev->priv; 1568 struct adm8211_priv *priv = dev->priv;
1556 1569
@@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev)
1562 free_irq(priv->pdev->irq, dev); 1575 free_irq(priv->pdev->irq, dev);
1563 1576
1564 adm8211_free_rings(dev); 1577 adm8211_free_rings(dev);
1565 return 0;
1566} 1578}
1567 1579
1568static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, 1580static 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)
1765 1777
1766static const struct ieee80211_ops adm8211_ops = { 1778static const struct ieee80211_ops adm8211_ops = {
1767 .tx = adm8211_tx, 1779 .tx = adm8211_tx,
1768 .open = adm8211_open, 1780 .start = adm8211_start,
1769 .stop = adm8211_stop, 1781 .stop = adm8211_stop,
1770 .add_interface = adm8211_add_interface, 1782 .add_interface = adm8211_add_interface,
1771 .remove_interface = adm8211_remove_interface, 1783 .remove_interface = adm8211_remove_interface,
1772 .config = adm8211_config, 1784 .config = adm8211_config,
1773 .config_interface = adm8211_config_interface, 1785 .config_interface = adm8211_config_interface,
1774 .set_multicast_list = adm8211_set_rx_mode, 1786 .configure_filter = adm8211_configure_filter,
1775 .get_stats = adm8211_get_stats, 1787 .get_stats = adm8211_get_stats,
1776 .get_tx_stats = adm8211_get_tx_stats, 1788 .get_tx_stats = adm8211_get_tx_stats,
1777 .get_tsf = adm8211_get_tsft 1789 .get_tsf = adm8211_get_tsft
@@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
1905 priv->tx_power = 0x40; 1917 priv->tx_power = 0x40;
1906 priv->lpf_cutoff = 0xFF; 1918 priv->lpf_cutoff = 0xFF;
1907 priv->lnags_threshold = 0xFF; 1919 priv->lnags_threshold = 0xFF;
1908 priv->mode = IEEE80211_IF_TYPE_MGMT; 1920 priv->mode = IEEE80211_IF_TYPE_MNTR;
1909 1921
1910 /* Power-on issue. EEPROM won't read correctly without */ 1922 /* Power-on issue. EEPROM won't read correctly without */
1911 if (priv->revid >= ADM8211_REV_BA) { 1923 if (priv->revid >= ADM8211_REV_BA) {
@@ -2000,7 +2012,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
2000 struct ieee80211_hw *dev = pci_get_drvdata(pdev); 2012 struct ieee80211_hw *dev = pci_get_drvdata(pdev);
2001 struct adm8211_priv *priv = dev->priv; 2013 struct adm8211_priv *priv = dev->priv;
2002 2014
2003 if (priv->mode != IEEE80211_IF_TYPE_MGMT) { 2015 if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
2004 ieee80211_stop_queues(dev); 2016 ieee80211_stop_queues(dev);
2005 adm8211_stop(dev); 2017 adm8211_stop(dev);
2006 } 2018 }
@@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev)
2018 pci_set_power_state(pdev, PCI_D0); 2030 pci_set_power_state(pdev, PCI_D0);
2019 pci_restore_state(pdev); 2031 pci_restore_state(pdev);
2020 2032
2021 if (priv->mode != IEEE80211_IF_TYPE_MGMT) { 2033 if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
2022 adm8211_open(dev); 2034 adm8211_start(dev);
2023 ieee80211_start_queues(dev); 2035 ieee80211_start_queues(dev);
2024 } 2036 }
2025 2037