aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-04-28 10:27:10 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-05-06 13:46:23 -0400
commit2c46f72e069eef5e98f2b04df08cde6bdc673aa7 (patch)
tree62243e8844fd39864bffacbd50b393d1470b8000
parent94b00658ffc719427c9c09d7920957bc35915c6f (diff)
iwlagn: check DMA mapping errors
DMA mappings can fail, but the current code doesn't check for that. Add checking, which requires some restructuring for proper error paths. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c13
2 files changed, 45 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 26601b7048f2..7c1becf9e2c1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -537,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
537 struct iwl_tx_cmd *tx_cmd; 537 struct iwl_tx_cmd *tx_cmd;
538 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; 538 struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
539 int txq_id; 539 int txq_id;
540 dma_addr_t phys_addr; 540 dma_addr_t phys_addr = 0;
541 dma_addr_t txcmd_phys; 541 dma_addr_t txcmd_phys;
542 dma_addr_t scratch_phys; 542 dma_addr_t scratch_phys;
543 u16 len, firstlen, secondlen; 543 u16 len, firstlen, secondlen;
@@ -564,7 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
564 spin_lock_irqsave(&priv->lock, flags); 564 spin_lock_irqsave(&priv->lock, flags);
565 if (iwl_is_rfkill(priv)) { 565 if (iwl_is_rfkill(priv)) {
566 IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); 566 IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
567 goto drop_unlock; 567 goto drop_unlock_priv;
568 } 568 }
569 569
570 fc = hdr->frame_control; 570 fc = hdr->frame_control;
@@ -585,7 +585,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
585 if (sta_id == IWL_INVALID_STATION) { 585 if (sta_id == IWL_INVALID_STATION) {
586 IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", 586 IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
587 hdr->addr1); 587 hdr->addr1);
588 goto drop_unlock; 588 goto drop_unlock_priv;
589 } 589 }
590 590
591 IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); 591 IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -628,10 +628,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
628 if (ieee80211_is_data_qos(fc)) { 628 if (ieee80211_is_data_qos(fc)) {
629 qc = ieee80211_get_qos_ctl(hdr); 629 qc = ieee80211_get_qos_ctl(hdr);
630 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 630 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
631 if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { 631
632 spin_unlock(&priv->sta_lock); 632 if (WARN_ON_ONCE(tid >= MAX_TID_COUNT))
633 goto drop_unlock; 633 goto drop_unlock_sta;
634 } 634
635 seq_number = priv->stations[sta_id].tid[tid].seq_number; 635 seq_number = priv->stations[sta_id].tid[tid].seq_number;
636 seq_number &= IEEE80211_SCTL_SEQ; 636 seq_number &= IEEE80211_SCTL_SEQ;
637 hdr->seq_ctrl = hdr->seq_ctrl & 637 hdr->seq_ctrl = hdr->seq_ctrl &
@@ -649,18 +649,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
649 txq = &priv->txq[txq_id]; 649 txq = &priv->txq[txq_id];
650 q = &txq->q; 650 q = &txq->q;
651 651
652 if (unlikely(iwl_queue_space(q) < q->high_mark)) { 652 if (unlikely(iwl_queue_space(q) < q->high_mark))
653 spin_unlock(&priv->sta_lock); 653 goto drop_unlock_sta;
654 goto drop_unlock;
655 }
656
657 if (ieee80211_is_data_qos(fc)) {
658 priv->stations[sta_id].tid[tid].tfds_in_queue++;
659 if (!ieee80211_has_morefrags(fc))
660 priv->stations[sta_id].tid[tid].seq_number = seq_number;
661 }
662
663 spin_unlock(&priv->sta_lock);
664 654
665 /* Set up driver data for this TFD */ 655 /* Set up driver data for this TFD */
666 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); 656 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -724,12 +714,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
724 txcmd_phys = pci_map_single(priv->pci_dev, 714 txcmd_phys = pci_map_single(priv->pci_dev,
725 &out_cmd->hdr, firstlen, 715 &out_cmd->hdr, firstlen,
726 PCI_DMA_BIDIRECTIONAL); 716 PCI_DMA_BIDIRECTIONAL);
717 if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys)))
718 goto drop_unlock_sta;
727 dma_unmap_addr_set(out_meta, mapping, txcmd_phys); 719 dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
728 dma_unmap_len_set(out_meta, len, firstlen); 720 dma_unmap_len_set(out_meta, len, firstlen);
729 /* Add buffer containing Tx command and MAC(!) header to TFD's
730 * first entry */
731 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
732 txcmd_phys, firstlen, 1, 0);
733 721
734 if (!ieee80211_has_morefrags(hdr->frame_control)) { 722 if (!ieee80211_has_morefrags(hdr->frame_control)) {
735 txq->need_update = 1; 723 txq->need_update = 1;
@@ -744,10 +732,30 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
744 if (secondlen > 0) { 732 if (secondlen > 0) {
745 phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, 733 phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
746 secondlen, PCI_DMA_TODEVICE); 734 secondlen, PCI_DMA_TODEVICE);
735 if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
736 pci_unmap_single(priv->pci_dev,
737 dma_unmap_addr(out_meta, mapping),
738 dma_unmap_len(out_meta, len),
739 PCI_DMA_BIDIRECTIONAL);
740 goto drop_unlock_sta;
741 }
742 }
743
744 if (ieee80211_is_data_qos(fc)) {
745 priv->stations[sta_id].tid[tid].tfds_in_queue++;
746 if (!ieee80211_has_morefrags(fc))
747 priv->stations[sta_id].tid[tid].seq_number = seq_number;
748 }
749
750 spin_unlock(&priv->sta_lock);
751
752 /* Attach buffers to TFD */
753 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
754 txcmd_phys, firstlen, 1, 0);
755 if (secondlen > 0)
747 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, 756 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
748 phys_addr, secondlen, 757 phys_addr, secondlen,
749 0, 0); 758 0, 0);
750 }
751 759
752 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + 760 scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
753 offsetof(struct iwl_tx_cmd, scratch); 761 offsetof(struct iwl_tx_cmd, scratch);
@@ -813,7 +821,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
813 821
814 return 0; 822 return 0;
815 823
816drop_unlock: 824drop_unlock_sta:
825 spin_unlock(&priv->sta_lock);
826drop_unlock_priv:
817 spin_unlock_irqrestore(&priv->lock, flags); 827 spin_unlock_irqrestore(&priv->lock, flags);
818 return -1; 828 return -1;
819} 829}
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 5a7cd177fe5e..e69597ea43e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -500,7 +500,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
500 } 500 }
501 501
502 memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ 502 memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
503 out_meta->flags = cmd->flags | CMD_MAPPED;
504 if (cmd->flags & CMD_WANT_SKB) 503 if (cmd->flags & CMD_WANT_SKB)
505 out_meta->source = cmd; 504 out_meta->source = cmd;
506 if (cmd->flags & CMD_ASYNC) 505 if (cmd->flags & CMD_ASYNC)
@@ -538,13 +537,20 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
538 q->write_ptr, idx, priv->cmd_queue); 537 q->write_ptr, idx, priv->cmd_queue);
539 } 538 }
540#endif 539#endif
541 txq->need_update = 1;
542
543 phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr, 540 phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
544 fix_size, PCI_DMA_BIDIRECTIONAL); 541 fix_size, PCI_DMA_BIDIRECTIONAL);
542 if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
543 idx = -ENOMEM;
544 goto out;
545 }
546
545 dma_unmap_addr_set(out_meta, mapping, phys_addr); 547 dma_unmap_addr_set(out_meta, mapping, phys_addr);
546 dma_unmap_len_set(out_meta, len, fix_size); 548 dma_unmap_len_set(out_meta, len, fix_size);
547 549
550 out_meta->flags = cmd->flags | CMD_MAPPED;
551
552 txq->need_update = 1;
553
548 trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags); 554 trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
549 555
550 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, 556 priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -555,6 +561,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
555 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 561 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
556 iwl_txq_update_write_ptr(priv, txq); 562 iwl_txq_update_write_ptr(priv, txq);
557 563
564 out:
558 spin_unlock_irqrestore(&priv->hcmd_lock, flags); 565 spin_unlock_irqrestore(&priv->hcmd_lock, flags);
559 return idx; 566 return idx;
560} 567}