From: Emmanuel Grumbach Date: Mon, 4 Jul 2011 05:58:19 +0000 (+0300) Subject: iwlagn: move the tasklet / irq to the transport layer X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=34c1b7ba127d1815b3dd1cb81cc4338ce0e712b7;p=openwrt%2Fstaging%2Fblogic.git iwlagn: move the tasklet / irq to the transport layer 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 Signed-off-by: Wey-Yi Guy --- diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index f1b40ec1c873..9a2eb1e426b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -49,6 +49,10 @@ void iwl_free_isr_ict(struct iwl_priv *priv) 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)); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 38a1e4f58829..598f16486aa6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -625,7 +625,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) } /* 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; @@ -3227,9 +3227,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) 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) @@ -3548,8 +3545,6 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops, 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); @@ -3558,6 +3553,10 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops, 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) ? @@ -3652,15 +3651,6 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops, /******************** * 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); @@ -3691,19 +3681,18 @@ int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops, 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; } @@ -3754,7 +3743,6 @@ void __devexit iwl_remove(struct iwl_priv * priv) iwl_eeprom_free(priv); - /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); @@ -3765,13 +3753,12 @@ void __devexit iwl_remove(struct iwl_priv * priv) 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index aed86c6cd933..70188550a4fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -188,6 +188,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 173fad2ab240..b38b00cebd2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1243,6 +1243,8 @@ struct iwl_trans; * @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); @@ -1261,6 +1263,8 @@ struct iwl_trans_ops { 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 { diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index acd2a5feec93..ecdda6d57b16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c @@ -705,6 +705,12 @@ static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb, 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, @@ -719,9 +725,28 @@ static const struct iwl_trans_ops trans_ops = { .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; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index f10bee8c1f88..f8133ea90aff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -115,4 +115,9 @@ static inline int trans_tx(struct iwl_priv *priv, struct sk_buff *skb, 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);