diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.c | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index cc3fc237d320..739087f3025c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c | |||
@@ -60,6 +60,8 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/interrupt.h> | ||
64 | |||
63 | #include "iwl-dev.h" | 65 | #include "iwl-dev.h" |
64 | #include "iwl-trans.h" | 66 | #include "iwl-trans.h" |
65 | #include "iwl-core.h" | 67 | #include "iwl-core.h" |
@@ -218,7 +220,7 @@ static int iwl_rx_init(struct iwl_priv *priv) | |||
218 | return 0; | 220 | return 0; |
219 | } | 221 | } |
220 | 222 | ||
221 | static void iwl_trans_rx_free(struct iwl_priv *priv) | 223 | static void iwl_trans_pcie_rx_free(struct iwl_priv *priv) |
222 | { | 224 | { |
223 | struct iwl_rx_queue *rxq = &priv->rxq; | 225 | struct iwl_rx_queue *rxq = &priv->rxq; |
224 | unsigned long flags; | 226 | unsigned long flags; |
@@ -453,7 +455,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) | |||
453 | * | 455 | * |
454 | * Destroy all TX DMA queues and structures | 456 | * Destroy all TX DMA queues and structures |
455 | */ | 457 | */ |
456 | static void iwl_trans_tx_free(struct iwl_priv *priv) | 458 | static void iwl_trans_pcie_tx_free(struct iwl_priv *priv) |
457 | { | 459 | { |
458 | int txq_id; | 460 | int txq_id; |
459 | 461 | ||
@@ -528,7 +530,7 @@ static int iwl_trans_tx_alloc(struct iwl_priv *priv) | |||
528 | return 0; | 530 | return 0; |
529 | 531 | ||
530 | error: | 532 | error: |
531 | trans_tx_free(&priv->trans); | 533 | iwl_trans_tx_free(trans(priv)); |
532 | 534 | ||
533 | return ret; | 535 | return ret; |
534 | } | 536 | } |
@@ -572,7 +574,7 @@ static int iwl_tx_init(struct iwl_priv *priv) | |||
572 | error: | 574 | error: |
573 | /*Upon error, free only if we allocated something */ | 575 | /*Upon error, free only if we allocated something */ |
574 | if (alloc) | 576 | if (alloc) |
575 | trans_tx_free(&priv->trans); | 577 | iwl_trans_tx_free(trans(priv)); |
576 | return ret; | 578 | return ret; |
577 | } | 579 | } |
578 | 580 | ||
@@ -649,7 +651,7 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) | |||
649 | } | 651 | } |
650 | 652 | ||
651 | /* Note: returns standard 0/-ERROR code */ | 653 | /* Note: returns standard 0/-ERROR code */ |
652 | static int iwl_trans_prepare_card_hw(struct iwl_priv *priv) | 654 | static int iwl_trans_pcie_prepare_card_hw(struct iwl_priv *priv) |
653 | { | 655 | { |
654 | int ret; | 656 | int ret; |
655 | 657 | ||
@@ -677,14 +679,14 @@ static int iwl_trans_prepare_card_hw(struct iwl_priv *priv) | |||
677 | return ret; | 679 | return ret; |
678 | } | 680 | } |
679 | 681 | ||
680 | static int iwl_trans_start_device(struct iwl_priv *priv) | 682 | static int iwl_trans_pcie_start_device(struct iwl_priv *priv) |
681 | { | 683 | { |
682 | int ret; | 684 | int ret; |
683 | 685 | ||
684 | priv->ucode_owner = IWL_OWNERSHIP_DRIVER; | 686 | priv->ucode_owner = IWL_OWNERSHIP_DRIVER; |
685 | 687 | ||
686 | if ((priv->cfg->sku & EEPROM_SKU_CAP_AMT_ENABLE) && | 688 | if ((priv->cfg->sku & EEPROM_SKU_CAP_AMT_ENABLE) && |
687 | iwl_trans_prepare_card_hw(priv)) { | 689 | iwl_trans_pcie_prepare_card_hw(priv)) { |
688 | IWL_WARN(priv, "Exit HW not ready\n"); | 690 | IWL_WARN(priv, "Exit HW not ready\n"); |
689 | return -EIO; | 691 | return -EIO; |
690 | } | 692 | } |
@@ -768,7 +770,7 @@ static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { | |||
768 | { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, | 770 | { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, |
769 | { IWL_TX_FIFO_AUX, IWL_AC_UNSET, }, | 771 | { IWL_TX_FIFO_AUX, IWL_AC_UNSET, }, |
770 | }; | 772 | }; |
771 | static void iwl_trans_tx_start(struct iwl_priv *priv) | 773 | static void iwl_trans_pcie_tx_start(struct iwl_priv *priv) |
772 | { | 774 | { |
773 | const struct queue_to_fifo_ac *queue_to_fifo; | 775 | const struct queue_to_fifo_ac *queue_to_fifo; |
774 | struct iwl_rxon_context *ctx; | 776 | struct iwl_rxon_context *ctx; |
@@ -916,7 +918,7 @@ static int iwl_trans_tx_stop(struct iwl_priv *priv) | |||
916 | return 0; | 918 | return 0; |
917 | } | 919 | } |
918 | 920 | ||
919 | static void iwl_trans_stop_device(struct iwl_priv *priv) | 921 | static void iwl_trans_pcie_stop_device(struct iwl_priv *priv) |
920 | { | 922 | { |
921 | unsigned long flags; | 923 | unsigned long flags; |
922 | 924 | ||
@@ -927,7 +929,7 @@ static void iwl_trans_stop_device(struct iwl_priv *priv) | |||
927 | spin_lock_irqsave(&priv->shrd->lock, flags); | 929 | spin_lock_irqsave(&priv->shrd->lock, flags); |
928 | iwl_disable_interrupts(priv); | 930 | iwl_disable_interrupts(priv); |
929 | spin_unlock_irqrestore(&priv->shrd->lock, flags); | 931 | spin_unlock_irqrestore(&priv->shrd->lock, flags); |
930 | trans_sync_irq(&priv->trans); | 932 | iwl_trans_sync_irq(trans(priv)); |
931 | 933 | ||
932 | /* device going down, Stop using ICT table */ | 934 | /* device going down, Stop using ICT table */ |
933 | iwl_disable_ict(priv); | 935 | iwl_disable_ict(priv); |
@@ -956,7 +958,7 @@ static void iwl_trans_stop_device(struct iwl_priv *priv) | |||
956 | iwl_apm_stop(priv); | 958 | iwl_apm_stop(priv); |
957 | } | 959 | } |
958 | 960 | ||
959 | static struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_priv *priv, | 961 | static struct iwl_tx_cmd *iwl_trans_pcie_get_tx_cmd(struct iwl_priv *priv, |
960 | int txq_id) | 962 | int txq_id) |
961 | { | 963 | { |
962 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 964 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; |
@@ -980,7 +982,7 @@ static struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_priv *priv, | |||
980 | return &dev_cmd->cmd.tx; | 982 | return &dev_cmd->cmd.tx; |
981 | } | 983 | } |
982 | 984 | ||
983 | static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb, | 985 | static int iwl_trans_pcie_tx(struct iwl_priv *priv, struct sk_buff *skb, |
984 | struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu, | 986 | struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu, |
985 | struct iwl_rxon_context *ctx) | 987 | struct iwl_rxon_context *ctx) |
986 | { | 988 | { |
@@ -1109,71 +1111,88 @@ static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb, | |||
1109 | return 0; | 1111 | return 0; |
1110 | } | 1112 | } |
1111 | 1113 | ||
1112 | static void iwl_trans_kick_nic(struct iwl_priv *priv) | 1114 | static void iwl_trans_pcie_kick_nic(struct iwl_priv *priv) |
1113 | { | 1115 | { |
1114 | /* Remove all resets to allow NIC to operate */ | 1116 | /* Remove all resets to allow NIC to operate */ |
1115 | iwl_write32(priv, CSR_RESET, 0); | 1117 | iwl_write32(priv, CSR_RESET, 0); |
1116 | } | 1118 | } |
1117 | 1119 | ||
1118 | static void iwl_trans_sync_irq(struct iwl_priv *priv) | 1120 | static int iwl_trans_pcie_request_irq(struct iwl_trans *trans) |
1121 | { | ||
1122 | struct iwl_priv *priv = priv(trans); | ||
1123 | int err; | ||
1124 | |||
1125 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | ||
1126 | iwl_irq_tasklet, (unsigned long)priv); | ||
1127 | |||
1128 | iwl_alloc_isr_ict(priv); | ||
1129 | |||
1130 | err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED, | ||
1131 | DRV_NAME, priv); | ||
1132 | if (err) { | ||
1133 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus->irq); | ||
1134 | iwl_free_isr_ict(priv); | ||
1135 | return err; | ||
1136 | } | ||
1137 | |||
1138 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static void iwl_trans_pcie_sync_irq(struct iwl_priv *priv) | ||
1119 | { | 1143 | { |
1120 | /* wait to make sure we flush pending tasklet*/ | 1144 | /* wait to make sure we flush pending tasklet*/ |
1121 | synchronize_irq(priv->bus->irq); | 1145 | synchronize_irq(priv->bus->irq); |
1122 | tasklet_kill(&priv->irq_tasklet); | 1146 | tasklet_kill(&priv->irq_tasklet); |
1123 | } | 1147 | } |
1124 | 1148 | ||
1125 | static void iwl_trans_free(struct iwl_priv *priv) | 1149 | static void iwl_trans_pcie_free(struct iwl_priv *priv) |
1126 | { | 1150 | { |
1127 | free_irq(priv->bus->irq, priv); | 1151 | free_irq(priv->bus->irq, priv); |
1128 | iwl_free_isr_ict(priv); | 1152 | iwl_free_isr_ict(priv); |
1153 | kfree(trans(priv)); | ||
1154 | trans(priv) = NULL; | ||
1129 | } | 1155 | } |
1130 | 1156 | ||
1131 | static const struct iwl_trans_ops trans_ops = { | 1157 | const struct iwl_trans_ops trans_ops_pcie; |
1132 | .start_device = iwl_trans_start_device, | ||
1133 | .prepare_card_hw = iwl_trans_prepare_card_hw, | ||
1134 | .stop_device = iwl_trans_stop_device, | ||
1135 | |||
1136 | .tx_start = iwl_trans_tx_start, | ||
1137 | 1158 | ||
1138 | .rx_free = iwl_trans_rx_free, | 1159 | static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd) |
1139 | .tx_free = iwl_trans_tx_free, | 1160 | { |
1161 | struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) + | ||
1162 | sizeof(struct iwl_trans_pcie), | ||
1163 | GFP_KERNEL); | ||
1164 | if (iwl_trans) { | ||
1165 | iwl_trans->ops = &trans_ops_pcie; | ||
1166 | iwl_trans->shrd = shrd; | ||
1167 | } | ||
1140 | 1168 | ||
1141 | .send_cmd = iwl_send_cmd, | 1169 | return iwl_trans; |
1142 | .send_cmd_pdu = iwl_send_cmd_pdu, | 1170 | } |
1143 | 1171 | ||
1144 | .get_tx_cmd = iwl_trans_get_tx_cmd, | 1172 | const struct iwl_trans_ops trans_ops_pcie = { |
1145 | .tx = iwl_trans_tx, | 1173 | .alloc = iwl_trans_pcie_alloc, |
1174 | .request_irq = iwl_trans_pcie_request_irq, | ||
1175 | .start_device = iwl_trans_pcie_start_device, | ||
1176 | .prepare_card_hw = iwl_trans_pcie_prepare_card_hw, | ||
1177 | .stop_device = iwl_trans_pcie_stop_device, | ||
1146 | 1178 | ||
1147 | .txq_agg_disable = iwl_trans_txq_agg_disable, | 1179 | .tx_start = iwl_trans_pcie_tx_start, |
1148 | .txq_agg_setup = iwl_trans_txq_agg_setup, | ||
1149 | 1180 | ||
1150 | .kick_nic = iwl_trans_kick_nic, | 1181 | .rx_free = iwl_trans_pcie_rx_free, |
1182 | .tx_free = iwl_trans_pcie_tx_free, | ||
1151 | 1183 | ||
1152 | .sync_irq = iwl_trans_sync_irq, | 1184 | .send_cmd = iwl_trans_pcie_send_cmd, |
1153 | .free = iwl_trans_free, | 1185 | .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu, |
1154 | }; | ||
1155 | 1186 | ||
1156 | int iwl_trans_register(struct iwl_trans *trans, struct iwl_priv *priv) | 1187 | .get_tx_cmd = iwl_trans_pcie_get_tx_cmd, |
1157 | { | 1188 | .tx = iwl_trans_pcie_tx, |
1158 | int err; | ||
1159 | 1189 | ||
1160 | priv->trans.ops = &trans_ops; | 1190 | .txq_agg_disable = iwl_trans_pcie_txq_agg_disable, |
1161 | priv->trans.priv = priv; | 1191 | .txq_agg_setup = iwl_trans_pcie_txq_agg_setup, |
1162 | 1192 | ||
1163 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 1193 | .kick_nic = iwl_trans_pcie_kick_nic, |
1164 | iwl_irq_tasklet, (unsigned long)priv); | ||
1165 | 1194 | ||
1166 | iwl_alloc_isr_ict(priv); | 1195 | .sync_irq = iwl_trans_pcie_sync_irq, |
1167 | 1196 | .free = iwl_trans_pcie_free, | |
1168 | err = request_irq(priv->bus->irq, iwl_isr_ict, IRQF_SHARED, | 1197 | }; |
1169 | DRV_NAME, priv); | ||
1170 | if (err) { | ||
1171 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus->irq); | ||
1172 | iwl_free_isr_ict(priv); | ||
1173 | return err; | ||
1174 | } | ||
1175 | |||
1176 | INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); | ||
1177 | 1198 | ||
1178 | return 0; | ||
1179 | } | ||