ath5k: don't reset mcast filter when configuring the mode
[linux-2.6.git] / drivers / net / wireless / ath / ath5k / base.c
index acbcfc2..95a8e23 100644 (file)
@@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
 
 /* Known PCI ids */
 static const struct pci_device_id ath5k_pci_id_table[] = {
-       { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
-       { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
-       { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
-       { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
-       { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
-       { PCI_VDEVICE(3COM_2,  0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
-       { PCI_VDEVICE(3COM,    0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
-       { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
-       { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
-       { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
-       { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* PCI-E cards */
-       { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */
+       { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
+       { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
+       { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
+       { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
+       { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
+       { PCI_VDEVICE(3COM_2,  0x0013) }, /* 3com 5212 */
+       { PCI_VDEVICE(3COM,    0x0013) }, /* 3com 3CRDAG675 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
+       { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+       { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+       { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
@@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
                struct ieee80211_if_init_conf *conf);
 static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+                                  int mc_count, struct dev_addr_list *mc_list);
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
                unsigned int changed_flags,
                unsigned int *new_flags,
-               int mc_count, struct dev_mc_list *mclist);
+               u64 multicast);
 static int ath5k_set_key(struct ieee80211_hw *hw,
                enum set_key_cmd cmd,
                struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
        .add_interface  = ath5k_add_interface,
        .remove_interface = ath5k_remove_interface,
        .config         = ath5k_config,
+       .prepare_multicast = ath5k_prepare_multicast,
        .configure_filter = ath5k_configure_filter,
        .set_key        = ath5k_set_key,
        .get_stats      = ath5k_get_stats,
@@ -471,7 +474,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
                 * DMA to work so force a reasonable value here if it
                 * comes up zero.
                 */
-               csz = L1_CACHE_BYTES / sizeof(u32);
+               csz = L1_CACHE_BYTES >> 2;
                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
        }
        /*
@@ -544,7 +547,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
        __set_bit(ATH_STAT_INVALID, sc->status);
 
        sc->iobase = mem; /* So we can unmap it on detach */
-       sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
+       sc->common.cachelsz = csz << 2; /* convert to bytes */
        sc->opmode = NL80211_IFTYPE_STATION;
        sc->bintval = 1000;
        mutex_init(&sc->lock);
@@ -563,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
        }
 
        /* Initialize device */
-       sc->ah = ath5k_hw_attach(sc, id->driver_data);
+       sc->ah = ath5k_hw_attach(sc);
        if (IS_ERR(sc->ah)) {
                ret = PTR_ERR(sc->ah);
                goto err_irq;
@@ -715,9 +718,9 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath5k_softc *sc = hw->priv;
-       struct ath_regulatory *reg = &sc->ah->ah_regulatory;
+       struct ath_regulatory *regulatory = &sc->common.regulatory;
 
-       return ath_reg_notifier_apply(wiphy, request, reg);
+       return ath_reg_notifier_apply(wiphy, request, regulatory);
 }
 
 static int
@@ -725,6 +728,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 {
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
+       struct ath_regulatory *regulatory = &sc->common.regulatory;
        u8 mac[ETH_ALEN] = {};
        int ret;
 
@@ -814,9 +818,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        memset(sc->bssidmask, 0xff, ETH_ALEN);
        ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
 
-       ah->ah_regulatory.current_rd =
-               ah->ah_capabilities.cap_eeprom.ee_regdomain;
-       ret = ath_regd_init(&ah->ah_regulatory, hw->wiphy, ath5k_reg_notifier);
+       regulatory->current_rd = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+       ret = ath_regd_init(regulatory, hw->wiphy, ath5k_reg_notifier);
        if (ret) {
                ATH5K_ERR(sc, "can't initialize regulatory system\n");
                goto err_queues;
@@ -828,8 +831,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
                goto err_queues;
        }
 
-       if (!ath_is_world_regd(&sc->ah->ah_regulatory))
-               regulatory_hint(hw->wiphy, sc->ah->ah_regulatory.alpha2);
+       if (!ath_is_world_regd(regulatory))
+               regulatory_hint(hw->wiphy, regulatory->alpha2);
 
        ath5k_init_leds(sc);
 
@@ -1122,7 +1125,6 @@ ath5k_mode_setup(struct ath5k_softc *sc)
        /* configure operational mode */
        ath5k_hw_set_opmode(ah);
 
-       ath5k_hw_set_mcast_filter(ah, 0, 0);
        ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
 }
 
@@ -1151,27 +1153,20 @@ static
 struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
 {
        struct sk_buff *skb;
-       unsigned int off;
 
        /*
         * Allocate buffer with headroom_needed space for the
         * fake physical layer header at the start.
         */
-       skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
+       skb = ath_rxbuf_alloc(&sc->common,
+                             sc->rxbufsize + sc->common.cachelsz - 1,
+                             GFP_ATOMIC);
 
        if (!skb) {
                ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
-                               sc->rxbufsize + sc->cachelsz - 1);
+                               sc->rxbufsize + sc->common.cachelsz - 1);
                return NULL;
        }
-       /*
-        * Cache-line-align.  This is important (for the
-        * 5210 at least) as not doing so causes bogus data
-        * in rx'd frames.
-        */
-       off = ((unsigned long)skb->data) % sc->cachelsz;
-       if (off != 0)
-               skb_reserve(skb, sc->cachelsz - off);
 
        *skb_addr = pci_map_single(sc->pdev,
                skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
@@ -1613,10 +1608,10 @@ ath5k_rx_start(struct ath5k_softc *sc)
        struct ath5k_buf *bf;
        int ret;
 
-       sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
+       sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->common.cachelsz);
 
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
-               sc->cachelsz, sc->rxbufsize);
+               sc->common.cachelsz, sc->rxbufsize);
 
        spin_lock_bh(&sc->rxbuflock);
        sc->rxlink = NULL;
@@ -1745,7 +1740,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
 static void
 ath5k_tasklet_rx(unsigned long data)
 {
-       struct ieee80211_rx_status rxs = {};
+       struct ieee80211_rx_status *rxs;
        struct ath5k_rx_status rs = {};
        struct sk_buff *skb, *next_skb;
        dma_addr_t next_skb_addr;
@@ -1755,6 +1750,7 @@ ath5k_tasklet_rx(unsigned long data)
        int ret;
        int hdrlen;
        int padsize;
+       int rx_flag;
 
        spin_lock(&sc->rxbuflock);
        if (list_empty(&sc->rxbuf)) {
@@ -1762,7 +1758,7 @@ ath5k_tasklet_rx(unsigned long data)
                goto unlock;
        }
        do {
-               rxs.flag = 0;
+               rx_flag = 0;
 
                bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
                BUG_ON(bf->skb == NULL);
@@ -1806,7 +1802,7 @@ ath5k_tasklet_rx(unsigned long data)
                                        goto accept;
                        }
                        if (rs.rs_status & AR5K_RXERR_MIC) {
-                               rxs.flag |= RX_FLAG_MMIC_ERROR;
+                               rx_flag |= RX_FLAG_MMIC_ERROR;
                                goto accept;
                        }
 
@@ -1844,6 +1840,7 @@ accept:
                        memmove(skb->data + padsize, skb->data, hdrlen);
                        skb_pull(skb, padsize);
                }
+               rxs = IEEE80211_SKB_RXCB(skb);
 
                /*
                 * always extend the mac timestamp, since this information is
@@ -1865,41 +1862,40 @@ accept:
                 * impossible to comply to that. This affects IBSS merge only
                 * right now, so it's not too bad...
                 */
-               rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
-               rxs.flag |= RX_FLAG_TSFT;
+               rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
+               rxs->flag = rx_flag | RX_FLAG_TSFT;
 
-               rxs.freq = sc->curchan->center_freq;
-               rxs.band = sc->curband->band;
+               rxs->freq = sc->curchan->center_freq;
+               rxs->band = sc->curband->band;
 
-               rxs.noise = sc->ah->ah_noise_floor;
-               rxs.signal = rxs.noise + rs.rs_rssi;
+               rxs->noise = sc->ah->ah_noise_floor;
+               rxs->signal = rxs->noise + rs.rs_rssi;
 
                /* An rssi of 35 indicates you should be able use
                 * 54 Mbps reliably. A more elaborate scheme can be used
                 * here but it requires a map of SNR/throughput for each
                 * possible mode used */
-               rxs.qual = rs.rs_rssi * 100 / 35;
+               rxs->qual = rs.rs_rssi * 100 / 35;
 
                /* rssi can be more than 35 though, anything above that
                 * should be considered at 100% */
-               if (rxs.qual > 100)
-                       rxs.qual = 100;
+               if (rxs->qual > 100)
+                       rxs->qual = 100;
 
-               rxs.antenna = rs.rs_antenna;
-               rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
-               rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
+               rxs->antenna = rs.rs_antenna;
+               rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
+               rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
 
-               if (rxs.rate_idx >= 0 && rs.rs_rate ==
-                   sc->curband->bitrates[rxs.rate_idx].hw_value_short)
-                       rxs.flag |= RX_FLAG_SHORTPRE;
+               if (rxs->rate_idx >= 0 && rs.rs_rate ==
+                   sc->curband->bitrates[rxs->rate_idx].hw_value_short)
+                       rxs->flag |= RX_FLAG_SHORTPRE;
 
                ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
 
                /* check beacons in IBSS mode */
                if (sc->opmode == NL80211_IFTYPE_ADHOC)
-                       ath5k_check_ibss_tsf(sc, skb, &rxs);
+                       ath5k_check_ibss_tsf(sc, skb, rxs);
 
-               memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
                ieee80211_rx(sc->hw, skb);
 
                bf->skb = next_skb;
@@ -2860,6 +2856,37 @@ unlock:
        return ret;
 }
 
+static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
+                                  int mc_count, struct dev_addr_list *mclist)
+{
+       u32 mfilt[2], val;
+       int i;
+       u8 pos;
+
+       mfilt[0] = 0;
+       mfilt[1] = 1;
+
+       for (i = 0; i < mc_count; i++) {
+               if (!mclist)
+                       break;
+               /* calculate XOR of eight 6-bit values */
+               val = get_unaligned_le32(mclist->dmi_addr + 0);
+               pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+               val = get_unaligned_le32(mclist->dmi_addr + 3);
+               pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+               pos &= 0x3f;
+               mfilt[pos / 32] |= (1 << (pos % 32));
+               /* XXX: we might be able to just do this instead,
+               * but not sure, needs testing, if we do use this we'd
+               * neet to inform below to not reset the mcast */
+               /* ath5k_hw_set_mcast_filterindex(ah,
+                *      mclist->dmi_addr[5]); */
+               mclist = mclist->next;
+       }
+
+       return ((u64)(mfilt[1]) << 32) | mfilt[0];
+}
+
 #define SUPPORTED_FIF_FLAGS \
        FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
        FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2885,16 +2912,16 @@ unlock:
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
                unsigned int changed_flags,
                unsigned int *new_flags,
-               int mc_count, struct dev_mc_list *mclist)
+               u64 multicast)
 {
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
-       u32 mfilt[2], val, rfilt;
-       u8 pos;
-       int i;
+       u32 mfilt[2], rfilt;
 
-       mfilt[0] = 0;
-       mfilt[1] = 0;
+       mutex_lock(&sc->lock);
+
+       mfilt[0] = multicast;
+       mfilt[1] = multicast >> 32;
 
        /* Only deal with supported flags */
        changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -2920,24 +2947,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
        if (*new_flags & FIF_ALLMULTI) {
                mfilt[0] =  ~0;
                mfilt[1] =  ~0;
-       } else {
-               for (i = 0; i < mc_count; i++) {
-                       if (!mclist)
-                               break;
-                       /* calculate XOR of eight 6-bit values */
-                       val = get_unaligned_le32(mclist->dmi_addr + 0);
-                       pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-                       val = get_unaligned_le32(mclist->dmi_addr + 3);
-                       pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-                       pos &= 0x3f;
-                       mfilt[pos / 32] |= (1 << (pos % 32));
-                       /* XXX: we might be able to just do this instead,
-                       * but not sure, needs testing, if we do use this we'd
-                       * neet to inform below to not reset the mcast */
-                       /* ath5k_hw_set_mcast_filterindex(ah,
-                        *      mclist->dmi_addr[5]); */
-                       mclist = mclist->next;
-               }
        }
 
        /* This is the best we can do */
@@ -2961,22 +2970,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
 
        /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
 
-       if (sc->opmode == NL80211_IFTYPE_MONITOR)
-               rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
-                       AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
-       if (sc->opmode != NL80211_IFTYPE_STATION)
-               rfilt |= AR5K_RX_FILTER_PROBEREQ;
-       if (sc->opmode != NL80211_IFTYPE_AP &&
-               sc->opmode != NL80211_IFTYPE_MESH_POINT &&
-               test_bit(ATH_STAT_PROMISC, sc->status))
-               rfilt |= AR5K_RX_FILTER_PROM;
-       if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
-               sc->opmode == NL80211_IFTYPE_ADHOC ||
-               sc->opmode == NL80211_IFTYPE_AP)
-               rfilt |= AR5K_RX_FILTER_BEACON;
-       if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
-               rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
-                       AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
+       switch (sc->opmode) {
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_MONITOR:
+               rfilt |= AR5K_RX_FILTER_CONTROL |
+                        AR5K_RX_FILTER_BEACON |
+                        AR5K_RX_FILTER_PROBEREQ |
+                        AR5K_RX_FILTER_PROM;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+               rfilt |= AR5K_RX_FILTER_PROBEREQ |
+                        AR5K_RX_FILTER_BEACON;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (sc->assoc)
+                       rfilt |= AR5K_RX_FILTER_BEACON;
+       default:
+               break;
+       }
 
        /* Set filters */
        ath5k_hw_set_rx_filter(ah, rfilt);
@@ -2986,6 +2998,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
        /* Set the cached hw filter flags, this will alter actually
         * be set in HW */
        sc->filter_flags = rfilt;
+
+       mutex_unlock(&sc->lock);
 }
 
 static int
@@ -3007,6 +3021,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        case ALG_TKIP:
                break;
        case ALG_CCMP:
+               if (sc->ah->ah_aes_support)
+                       break;
+
                return -EOPNOTSUPP;
        default:
                WARN_ON(1);