PCIe doesn't provide any ISR registration API, whereas other buses do.
Hence, we need to move the tasklet and irq to the transport layer to allow this
flexibility.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
priv->_agn.ict_tbl_vir,
priv->_agn.ict_tbl_dma);
priv->_agn.ict_tbl_vir = NULL;
+ memset(&priv->_agn.ict_tbl_dma, 0,
+ sizeof(priv->_agn.ict_tbl_dma));
+ memset(&priv->_agn.aligned_ict_tbl_dma, 0,
+ sizeof(priv->_agn.aligned_ict_tbl_dma));
}
}
}
/* tasklet for iwlagn interrupt */
-static void iwl_irq_tasklet(struct iwl_priv *priv)
+void iwl_irq_tasklet(struct iwl_priv *priv)
{
u32 inta = 0;
u32 handled = 0;
init_timer(&priv->watchdog);
priv->watchdog.data = (unsigned long)priv;
priv->watchdog.function = iwl_bg_watchdog;
-
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
- iwl_irq_tasklet, (unsigned long)priv);
}
static void iwl_cancel_deferred_work(struct iwl_priv *priv)
priv->bus.ops->set_drv_data(&priv->bus, priv);
priv->bus.dev = priv->bus.ops->get_dev(&priv->bus);
- iwl_trans_register(&priv->trans);
-
/* At this point both hw and priv are allocated. */
SET_IEEE80211_DEV(hw, priv->bus.dev);
priv->cfg = cfg;
priv->inta_mask = CSR_INI_SET_MASK;
+ err = iwl_trans_register(priv);
+ if (err)
+ goto out_free_priv;
+
/* is antenna coupling more than 35dB ? */
priv->bt_ant_couple_ok =
(iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ?
/********************
* 7. Setup services
********************/
- iwl_alloc_isr_ict(priv);
-
- err = request_irq(priv->bus.irq, iwl_isr_ict, IRQF_SHARED,
- DRV_NAME, priv);
- if (err) {
- IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus.irq);
- goto out_uninit_drv;
- }
-
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
iwl_testmode_init(priv);
return 0;
- out_destroy_workqueue:
+out_destroy_workqueue:
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
- free_irq(priv->bus.irq, priv);
- iwl_free_isr_ict(priv);
- out_uninit_drv:
iwl_uninit_drv(priv);
- out_free_eeprom:
+out_free_eeprom:
iwl_eeprom_free(priv);
- out_free_traffic_mem:
+out_free_traffic_mem:
iwl_free_traffic_mem(priv);
+ trans_free(priv);
+out_free_priv:
ieee80211_free_hw(priv->hw);
- out:
+out:
return err;
}
iwl_eeprom_free(priv);
-
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
priv->workqueue = NULL;
iwl_free_traffic_mem(priv);
- free_irq(priv->bus.irq, priv);
+ trans_free(priv);
+
priv->bus.ops->set_drv_data(&priv->bus, NULL);
iwl_uninit_drv(priv);
- iwl_free_isr_ict(priv);
-
dev_kfree_skb(priv->beacon_skb);
ieee80211_free_hw(priv->hw);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
/* rx */
+void iwl_irq_tasklet(struct iwl_priv *priv);
void iwlagn_rx_queue_restock(struct iwl_priv *priv);
void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
void iwlagn_rx_replenish(struct iwl_priv *priv);
* @tx_free: frees the tx memory
* @send_cmd:send a host command
* @send_cmd_pdu:send a host command: flags can be CMD_*
+ * @free: release all the ressource for the transport layer itself such as
+ * irq, tasklet etc...
*/
struct iwl_trans_ops {
int (*rx_init)(struct iwl_priv *priv);
int (*tx)(struct iwl_priv *priv, struct sk_buff *skb,
struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu,
struct iwl_rxon_context *ctx);
+
+ void (*free)(struct iwl_priv *priv);
};
struct iwl_trans {
return 0;
}
+static void iwl_trans_free(struct iwl_priv *priv)
+{
+ free_irq(priv->bus.irq, priv);
+ iwl_free_isr_ict(priv);
+}
+
static const struct iwl_trans_ops trans_ops = {
.rx_init = iwl_trans_rx_init,
.rx_stop = iwl_trans_rx_stop,
.get_tx_cmd = iwl_trans_get_tx_cmd,
.tx = iwl_trans_tx,
+
+ .free = iwl_trans_free,
};
-void iwl_trans_register(struct iwl_trans *trans)
+int iwl_trans_register(struct iwl_priv *priv)
{
- trans->ops = &trans_ops;
+ int err;
+
+ priv->trans.ops = &trans_ops;
+
+ iwl_alloc_isr_ict(priv);
+
+ err = request_irq(priv->bus.irq, iwl_isr_ict, IRQF_SHARED,
+ DRV_NAME, priv);
+ if (err) {
+ IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus.irq);
+ iwl_free_isr_ict(priv);
+ return err;
+ }
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+
+ return 0;
}
return priv->trans.ops->tx(priv, skb, tx_cmd, txq_id, fc, ampdu, ctx);
}
-void iwl_trans_register(struct iwl_trans *trans);
+static inline void trans_free(struct iwl_priv *priv)
+{
+ priv->trans.ops->free(priv);
+}
+
+int iwl_trans_register(struct iwl_priv *priv);