Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c46f72e authored by Johannes Berg's avatar Johannes Berg Committed by Wey-Yi Guy
Browse files

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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent 94b00658
Loading
Loading
Loading
Loading
+35 −25
Original line number Diff line number Diff line
@@ -537,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
	struct iwl_tx_cmd *tx_cmd;
	struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
	int txq_id;
	dma_addr_t phys_addr;
	dma_addr_t phys_addr = 0;
	dma_addr_t txcmd_phys;
	dma_addr_t scratch_phys;
	u16 len, firstlen, secondlen;
@@ -564,7 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
	spin_lock_irqsave(&priv->lock, flags);
	if (iwl_is_rfkill(priv)) {
		IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
		goto drop_unlock;
		goto drop_unlock_priv;
	}

	fc = hdr->frame_control;
@@ -585,7 +585,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
	if (sta_id == IWL_INVALID_STATION) {
		IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
			       hdr->addr1);
		goto drop_unlock;
		goto drop_unlock_priv;
	}

	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)
	if (ieee80211_is_data_qos(fc)) {
		qc = ieee80211_get_qos_ctl(hdr);
		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
		if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
			spin_unlock(&priv->sta_lock);
			goto drop_unlock;
		}

		if (WARN_ON_ONCE(tid >= MAX_TID_COUNT))
			goto drop_unlock_sta;

		seq_number = priv->stations[sta_id].tid[tid].seq_number;
		seq_number &= IEEE80211_SCTL_SEQ;
		hdr->seq_ctrl = hdr->seq_ctrl &
@@ -649,18 +649,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
	txq = &priv->txq[txq_id];
	q = &txq->q;

	if (unlikely(iwl_queue_space(q) < q->high_mark)) {
		spin_unlock(&priv->sta_lock);
		goto drop_unlock;
	}

	if (ieee80211_is_data_qos(fc)) {
		priv->stations[sta_id].tid[tid].tfds_in_queue++;
		if (!ieee80211_has_morefrags(fc))
			priv->stations[sta_id].tid[tid].seq_number = seq_number;
	}

	spin_unlock(&priv->sta_lock);
	if (unlikely(iwl_queue_space(q) < q->high_mark))
		goto drop_unlock_sta;

	/* Set up driver data for this TFD */
	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)
	txcmd_phys = pci_map_single(priv->pci_dev,
				    &out_cmd->hdr, firstlen,
				    PCI_DMA_BIDIRECTIONAL);
	if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys)))
		goto drop_unlock_sta;
	dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
	dma_unmap_len_set(out_meta, len, firstlen);
	/* Add buffer containing Tx command and MAC(!) header to TFD's
	 * first entry */
	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
						   txcmd_phys, firstlen, 1, 0);

	if (!ieee80211_has_morefrags(hdr->frame_control)) {
		txq->need_update = 1;
@@ -744,10 +732,30 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
	if (secondlen > 0) {
		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
					   secondlen, PCI_DMA_TODEVICE);
		if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
			pci_unmap_single(priv->pci_dev,
					 dma_unmap_addr(out_meta, mapping),
					 dma_unmap_len(out_meta, len),
					 PCI_DMA_BIDIRECTIONAL);
			goto drop_unlock_sta;
		}
	}

	if (ieee80211_is_data_qos(fc)) {
		priv->stations[sta_id].tid[tid].tfds_in_queue++;
		if (!ieee80211_has_morefrags(fc))
			priv->stations[sta_id].tid[tid].seq_number = seq_number;
	}

	spin_unlock(&priv->sta_lock);

	/* Attach buffers to TFD */
	priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
						   txcmd_phys, firstlen, 1, 0);
	if (secondlen > 0)
		priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
							   phys_addr, secondlen,
							   0, 0);
	}

	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
				offsetof(struct iwl_tx_cmd, scratch);
@@ -813,7 +821,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)

	return 0;

drop_unlock:
drop_unlock_sta:
	spin_unlock(&priv->sta_lock);
drop_unlock_priv:
	spin_unlock_irqrestore(&priv->lock, flags);
	return -1;
}
+10 −3
Original line number Diff line number Diff line
@@ -500,7 +500,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
	}

	memset(out_meta, 0, sizeof(*out_meta));	/* re-initialize to NULL */
	out_meta->flags = cmd->flags | CMD_MAPPED;
	if (cmd->flags & CMD_WANT_SKB)
		out_meta->source = cmd;
	if (cmd->flags & CMD_ASYNC)
@@ -538,13 +537,20 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
				q->write_ptr, idx, priv->cmd_queue);
	}
#endif
	txq->need_update = 1;

	phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
				   fix_size, PCI_DMA_BIDIRECTIONAL);
	if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
		idx = -ENOMEM;
		goto out;
	}

	dma_unmap_addr_set(out_meta, mapping, phys_addr);
	dma_unmap_len_set(out_meta, len, fix_size);

	out_meta->flags = cmd->flags | CMD_MAPPED;

	txq->need_update = 1;

	trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);

	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)
	q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
	iwl_txq_update_write_ptr(priv, txq);

 out:
	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
	return idx;
}