]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/p54/p54common.c
Merge branch 'fix/hda' into for-linus
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / p54 / p54common.c
index a4e99b02af021b81f7061d4659741df6ef86860e..c6a370fa9bcbf11115fdd9063327356339f4504d 100644 (file)
@@ -138,6 +138,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
        u8 *fw_version = NULL;
        size_t len;
        int i;
+       int maxlen;
 
        if (priv->rx_start)
                return 0;
@@ -195,6 +196,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
                        else
                                priv->rx_mtu = (size_t)
                                        0x620 - priv->tx_hdr_len;
+                       maxlen = priv->tx_hdr_len + /* USB devices */
+                                sizeof(struct p54_rx_data) +
+                                4 + /* rx alignment */
+                                IEEE80211_MAX_FRAG_THRESHOLD;
+                       if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+                               printk(KERN_INFO "p54: rx_mtu reduced from %d "
+                                                "to %d\n", priv->rx_mtu,
+                                                maxlen);
+                               priv->rx_mtu = maxlen;
+                       }
                        break;
                        }
                case BR_CODE_EXPOSED_IF:
@@ -335,6 +346,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
                               "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
 static int p54_init_xbow_synth(struct ieee80211_hw *dev);
 
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+                            u16 type)
+{
+       struct p54_common *priv = dev->priv;
+       int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+       int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+       int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+       int i;
+
+       if (len != (entry_size * num_entries)) {
+               printk(KERN_ERR "%s: unknown rssi calibration data packing "
+                                " type:(%x) len:%d.\n",
+                      wiphy_name(dev->wiphy), type, len);
+
+               print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+                                    data, len);
+
+               printk(KERN_ERR "%s: please report this issue.\n",
+                       wiphy_name(dev->wiphy));
+               return;
+       }
+
+       for (i = 0; i < num_entries; i++) {
+               struct pda_rssi_cal_entry *cal = data +
+                                                (offset + i * entry_size);
+               priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+               priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+       }
+}
+
 static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 {
        struct p54_common *priv = dev->priv;
@@ -434,6 +475,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
                        priv->version = *(u8 *)(entry->data + 1);
                        break;
+               case PDR_RSSI_LINEAR_APPROXIMATION:
+               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+                       p54_parse_rssical(dev, entry->data, data_len,
+                                         le16_to_cpu(entry->code));
+                       break;
                case PDR_END:
                        /* make it overrun */
                        entry_len = len;
@@ -453,10 +500,7 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                case PDR_DEFAULT_COUNTRY:
                case PDR_ANTENNA_GAIN:
                case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
-               case PDR_RSSI_LINEAR_APPROXIMATION:
-               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
                case PDR_REGULATORY_POWER_LIMITS:
-               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
                case PDR_RADIATED_TRANSMISSION_CORRECTION:
                case PDR_PRISM_TX_IQ_CALIBRATION:
                case PDR_BASEBAND_REGISTERS:
@@ -527,8 +571,11 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 
 static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 {
-       /* TODO: get the rssi_add & rssi_mul data from the eeprom */
-       return ((rssi * 0x83) / 64 - 400) / 4;
+       struct p54_common *priv = dev->priv;
+       int band = dev->conf.channel->band;
+
+       return ((rssi * priv->rssical_db[band].mul) / 64 +
+                        priv->rssical_db[band].add) / 4;
 }
 
 static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -539,6 +586,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
        u16 freq = le16_to_cpu(hdr->freq);
        size_t header_len = sizeof(*hdr);
        u32 tsf32;
+       u8 rate = hdr->rate & 0xf;
 
        /*
         * If the device is in a unspecified state we have to
@@ -567,8 +615,11 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
        rx_status.qual = (100 * hdr->rssi) / 127;
        if (hdr->rate & 0x10)
                rx_status.flag |= RX_FLAG_SHORTPRE;
-       rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
-                       hdr->rate : (hdr->rate - 4)) & 0xf;
+       if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+               rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
+       else
+               rx_status.rate_idx = rate;
+
        rx_status.freq = freq;
        rx_status.band =  dev->conf.channel->band;
        rx_status.antenna = hdr->antenna;
@@ -589,6 +640,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 
        ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
+       queue_delayed_work(dev->workqueue, &priv->work,
+                          msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
        return -1;
 }
 
@@ -644,7 +698,7 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
                freed = priv->rx_end - last_addr;
        __skb_unlink(skb, &priv->tx_queue);
        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 
        if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 +
                     IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
@@ -652,6 +706,27 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(p54_free_skb);
 
+static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
+                                          __le32 req_id)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *entry = priv->tx_queue.next;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       while (entry != (struct sk_buff *)&priv->tx_queue) {
+               struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+               if (hdr->req_id == req_id) {
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       return entry;
+               }
+               entry = entry->next;
+       }
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+       return NULL;
+}
+
 static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct p54_common *priv = dev->priv;
@@ -696,6 +771,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                entry_hdr = (struct p54_hdr *) entry->data;
                entry_data = (struct p54_tx_data *) entry_hdr->data;
                priv->tx_stats[entry_data->hw_queue].len--;
+               priv->stats.dot11ACKFailureCount += payload->tries - 1;
 
                if (unlikely(entry == priv->cached_beacon)) {
                        kfree_skb(entry);
@@ -737,6 +813,16 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                        info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                info->status.ack_signal = p54_rssi_to_dbm(dev,
                                (int)payload->ack_rssi);
+
+               if (entry_data->key_type == P54_CRYPTO_TKIPMICHAEL) {
+                       u8 *iv = (u8 *)(entry_data->align + pad +
+                                       entry_data->crypt_offset);
+
+                       /* Restore the original TKIP IV. */
+                       iv[2] = iv[0];
+                       iv[0] = iv[1];
+                       iv[1] = (iv[0] | 0x20) & 0x7f;  /* WEPSeed - 8.3.2.2 */
+               }
                skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
                ieee80211_tx_status_irqsafe(dev, entry);
                goto out;
@@ -775,8 +861,12 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct p54_common *priv = dev->priv;
        struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
        struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
-       u32 tsf32 = le32_to_cpu(stats->tsf32);
+       u32 tsf32;
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
 
+       tsf32 = le32_to_cpu(stats->tsf32);
        if (tsf32 < priv->tsf_low32)
                priv->tsf_high32++;
        priv->tsf_low32 = tsf32;
@@ -786,9 +876,8 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
        priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
 
        priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-       complete(&priv->stats_comp);
 
-       mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
+       p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
 }
 
 static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
@@ -897,6 +986,8 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                 * have a few spare slots for control frames left.
                 */
                ieee80211_stop_queues(dev);
+               queue_delayed_work(dev->workqueue, &priv->work,
+                                  msecs_to_jiffies(P54_TX_TIMEOUT));
 
                if (unlikely(left == 32)) {
                        /*
@@ -1022,7 +1113,7 @@ int p54_read_eeprom(struct ieee80211_hw *dev)
                        eeprom_hdr->v2.magic2 = 0xf;
                        memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
                }
-               priv->tx(dev, skb, 0);
+               priv->tx(dev, skb);
 
                if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
                        printk(KERN_ERR "%s: device does not respond!\n",
@@ -1063,7 +1154,7 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
        tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
        tim->count = 1;
        tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
@@ -1081,7 +1172,7 @@ static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
 
        sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
        memcpy(sta->addr, addr, ETH_ALEN);
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
@@ -1124,7 +1215,7 @@ static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
        hdr = (void *)entry->data;
        cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
        cancel->req_id = hdr->req_id;
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
@@ -1317,7 +1408,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        hdr->tries = ridx;
        txhdr->rts_rate_idx = 0;
        if (info->control.hw_key) {
-               crypt_offset += info->control.hw_key->iv_len;
                txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
                txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
                memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
@@ -1331,6 +1421,8 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                }
                /* reserve some space for ICV */
                len += info->control.hw_key->icv_len;
+               memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+                      info->control.hw_key->icv_len);
        } else {
                txhdr->key_type = 0;
                txhdr->key_len = 0;
@@ -1353,7 +1445,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        /* modifies skb->cb and with it info, so must be last! */
        if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
                goto err;
-       priv->tx(dev, skb, 0);
+       priv->tx(dev, skb);
+
+       queue_delayed_work(dev->workqueue, &priv->work,
+                          msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
+
        return 0;
 
  err:
@@ -1428,19 +1524,19 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
                setup->v2.lpf_bandwidth = cpu_to_le16(65535);
                setup->v2.osc_start_delay = cpu_to_le16(65535);
        }
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
-                   u16 frequency)
+static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
 {
        struct p54_common *priv = dev->priv;
        struct sk_buff *skb;
        struct p54_scan *chan;
        unsigned int i;
        void *entry;
-       __le16 freq = cpu_to_le16(frequency);
+       __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
+       int band = dev->conf.channel->band;
 
        skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
                            sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
@@ -1501,15 +1597,15 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell,
        }
 
        if (priv->fw_var < 0x500) {
-               chan->v1.rssical_mul = cpu_to_le16(130);
-               chan->v1.rssical_add = cpu_to_le16(0xfe70);
+               chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+               chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add);
        } else {
-               chan->v2.rssical_mul = cpu_to_le16(130);
-               chan->v2.rssical_add = cpu_to_le16(0xfe70);
+               chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);
+               chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add);
                chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
                memset(chan->v2.rts_rates, 0, 8);
        }
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 
  err:
@@ -1535,7 +1631,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
        led->led_permanent = cpu_to_le16(link);
        led->led_temporary = cpu_to_le16(act);
        led->duration = cpu_to_le16(1000);
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
@@ -1575,21 +1671,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
        edcf->flags = 0;
        memset(edcf->mapping, 0, sizeof(edcf->mapping));
        memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
-       priv->tx(dev, skb, 1);
-       return 0;
-}
-
-static int p54_init_stats(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-
-       priv->cached_stats = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
-                       sizeof(struct p54_hdr) + sizeof(struct p54_statistics),
-                       P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
-       if (!priv->cached_stats)
-                       return -ENOMEM;
-
-       mod_timer(&priv->stats_timer, jiffies + HZ);
+       priv->tx(dev, skb);
        return 0;
 }
 
@@ -1684,9 +1766,6 @@ static int p54_start(struct ieee80211_hw *dev)
        P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
        P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
        err = p54_set_edcf(dev);
-       if (err)
-               goto out;
-       err = p54_init_stats(dev);
        if (err)
                goto out;
 
@@ -1698,6 +1777,8 @@ static int p54_start(struct ieee80211_hw *dev)
                goto out;
        }
 
+       queue_delayed_work(dev->workqueue, &priv->work, 0);
+
 out:
        mutex_unlock(&priv->conf_mutex);
        return err;
@@ -1710,9 +1791,7 @@ static void p54_stop(struct ieee80211_hw *dev)
 
        mutex_lock(&priv->conf_mutex);
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-       del_timer(&priv->stats_timer);
-       p54_free_skb(dev, priv->cached_stats);
-       priv->cached_stats = NULL;
+       cancel_delayed_work_sync(&priv->work);
        if (priv->cached_beacon)
                p54_tx_cancel(dev, priv->cached_beacon);
 
@@ -1771,7 +1850,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
 
 static int p54_config(struct ieee80211_hw *dev, u32 changed)
 {
-       int ret;
+       int ret = 0;
        struct p54_common *priv = dev->priv;
        struct ieee80211_conf *conf = &dev->conf;
 
@@ -1784,8 +1863,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
                        goto out;
        }
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ret = p54_scan(dev, P54_SCAN_EXIT, 0,
-                              conf->channel->center_freq);
+               ret = p54_scan(dev, P54_SCAN_EXIT, 0);
                if (ret)
                        goto out;
        }
@@ -1811,8 +1889,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
        }
 
        if (conf->changed & IEEE80211_IFCC_BEACON) {
-               ret = p54_scan(dev, P54_SCAN_EXIT, 0,
-                              dev->conf.channel->center_freq);
+               ret = p54_scan(dev, P54_SCAN_EXIT, 0);
                if (ret)
                        goto out;
                ret = p54_setup_mac(dev);
@@ -1885,18 +1962,33 @@ static int p54_init_xbow_synth(struct ieee80211_hw *dev)
        xbow->magic2 = cpu_to_le16(0x2);
        xbow->freq = cpu_to_le16(5390);
        memset(xbow->padding, 0, sizeof(xbow->padding));
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        return 0;
 }
 
-static void p54_statistics_timer(unsigned long data)
+static void p54_work(struct work_struct *work)
 {
-       struct ieee80211_hw *dev = (struct ieee80211_hw *) data;
-       struct p54_common *priv = dev->priv;
+       struct p54_common *priv = container_of(work, struct p54_common,
+                                              work.work);
+       struct ieee80211_hw *dev = priv->hw;
+       struct sk_buff *skb;
 
-       BUG_ON(!priv->cached_stats);
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
 
-       priv->tx(dev, priv->cached_stats, 0);
+       /*
+        * TODO: walk through tx_queue and do the following tasks
+        *      1. initiate bursts.
+        *      2. cancel stuck frames / reset the device if necessary.
+        */
+
+       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) +
+                           sizeof(struct p54_statistics),
+                           P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+       if (!skb)
+               return ;
+
+       priv->tx(dev, skb);
 }
 
 static int p54_get_stats(struct ieee80211_hw *dev,
@@ -1904,17 +1996,7 @@ static int p54_get_stats(struct ieee80211_hw *dev,
 {
        struct p54_common *priv = dev->priv;
 
-       del_timer(&priv->stats_timer);
-       p54_statistics_timer((unsigned long)dev);
-
-       if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) {
-               printk(KERN_ERR "%s: device does not respond!\n",
-                       wiphy_name(dev->wiphy));
-               return -EBUSY;
-       }
-
        memcpy(stats, &priv->stats, sizeof(*stats));
-
        return 0;
 }
 
@@ -1946,8 +2028,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
                        priv->basic_rate_mask = info->basic_rates;
                p54_setup_mac(dev);
                if (priv->fw_var >= 0x500)
-                       p54_scan(dev, P54_SCAN_EXIT, 0,
-                                dev->conf.channel->center_freq);
+                       p54_scan(dev, P54_SCAN_EXIT, 0);
        }
        if (changed & BSS_CHANGED_ASSOC) {
                if (info->assoc) {
@@ -2039,7 +2120,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
                        [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
        }
 
-       priv->tx(dev, skb, 1);
+       priv->tx(dev, skb);
        mutex_unlock(&priv->conf_mutex);
        return 0;
 }
@@ -2072,6 +2153,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
                return NULL;
 
        priv = dev->priv;
+       priv->hw = dev;
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
        priv->basic_rate_mask = 0x15f;
        skb_queue_head_init(&priv->tx_queue);
@@ -2107,9 +2189,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 
        mutex_init(&priv->conf_mutex);
        init_completion(&priv->eeprom_comp);
-       init_completion(&priv->stats_comp);
-       setup_timer(&priv->stats_timer, p54_statistics_timer,
-               (unsigned long)dev);
+       INIT_DELAYED_WORK(&priv->work, p54_work);
 
        return dev;
 }
@@ -2118,8 +2198,6 @@ EXPORT_SYMBOL_GPL(p54_init_common);
 void p54_free_common(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
-       del_timer(&priv->stats_timer);
-       kfree_skb(priv->cached_stats);
        kfree(priv->iq_autocal);
        kfree(priv->output_limit);
        kfree(priv->curve_data);