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

Commit 7050ec82 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville
Browse files

rt2x00: Split rt2x00lib_write_tx_desc()



Split rt2x00lib_write_tx_desc() up into a TX descriptor initializor
and TX descriptor writer.

This split is required to properly allow mac80211 to move its
tx_control structure into the skb->cb array.
The rt2x00queue_create_tx_descriptor() function will read all tx control
information and convert it into a rt2x00 TX descriptor information structure.
After that function is complete, we have all information we needed from the
tx control structure and are free to start writing into the skb->cb array
for our own purposes.
rt2x00queue_write_tx_descriptor() will be in charge of really sending
the TX descriptor to the hardware and kicking the TX queue.

Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4de36fe5
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1492,12 +1492,21 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
	struct rt2x00_intf *intf = vif_to_intf(control->vif);
	struct queue_entry_priv_pci_tx *priv_tx;
	struct skb_frame_desc *skbdesc;
	struct txentry_desc txdesc;
	u32 reg;

	if (unlikely(!intf->beacon))
		return -ENOBUFS;
	priv_tx = intf->beacon->priv_data;

	/*
	 * Copy all TX descriptor information into txdesc,
	 * after that we are free to use the skb->cb array
	 * for our information.
	 */
	intf->beacon->skb = skb;
	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control);

	/*
	 * Fill in skb descriptor
	 */
@@ -1525,8 +1534,8 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
	 * Write entire beacon with descriptor to register,
	 * and kick the beacon generator.
	 */
	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
	memcpy(priv_tx->data, skb->data, skb->len);
	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

	return 0;
+10 −1
Original line number Diff line number Diff line
@@ -1808,6 +1808,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
	struct rt2x00_intf *intf = vif_to_intf(control->vif);
	struct queue_entry_priv_pci_tx *priv_tx;
	struct skb_frame_desc *skbdesc;
	struct txentry_desc txdesc;
	u32 reg;

	if (unlikely(!intf->beacon))
@@ -1815,6 +1816,14 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,

	priv_tx = intf->beacon->priv_data;

	/*
	 * Copy all TX descriptor information into txdesc,
	 * after that we are free to use the skb->cb array
	 * for our information.
	 */
	intf->beacon->skb = skb;
	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control);

	/*
	 * Fill in skb descriptor
	 */
@@ -1842,8 +1851,8 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
	 * Write entire beacon with descriptor to register,
	 * and kick the beacon generator.
	 */
	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
	memcpy(priv_tx->data, skb->data, skb->len);
	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);

	return 0;
+10 −1
Original line number Diff line number Diff line
@@ -1676,6 +1676,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
	struct rt2x00_intf *intf = vif_to_intf(control->vif);
	struct queue_entry_priv_usb_bcn *priv_bcn;
	struct skb_frame_desc *skbdesc;
	struct txentry_desc txdesc;
	int pipe = usb_sndbulkpipe(usb_dev, 1);
	int length;
	u16 reg;
@@ -1685,6 +1686,14 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,

	priv_bcn = intf->beacon->priv_data;

	/*
	 * Copy all TX descriptor information into txdesc,
	 * after that we are free to use the skb->cb array
	 * for our information.
	 */
	intf->beacon->skb = skb;
	rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc, control);

	/*
	 * Add the descriptor in front of the skb.
	 */
@@ -1713,7 +1722,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);

	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
	rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);

	/*
	 * USB devices cannot blindly pass the skb->len as the
+35 −7
Original line number Diff line number Diff line
@@ -926,6 +926,41 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
	return ((size * 8 * 10) % rate);
}

/**
 * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
 * @entry: The entry which will be used to transfer the TX frame.
 * @txdesc: rt2x00 TX descriptor which will be initialized by this function.
 * @control: mac80211 TX control structure from where we read the information.
 *
 * This function will initialize the &struct txentry_desc based on information
 * from mac80211. This descriptor can then be used by rt2x00lib and the drivers
 * to correctly initialize the hardware descriptor.
 * Note that before calling this function the skb->cb array must be untouched
 * by rt2x00lib. Only after this function completes will it be save to
 * overwrite the skb->cb information.
 * The reason for this is that mac80211 writes its own tx information into
 * the skb->cb array, and this function will use that information to initialize
 * the &struct txentry_desc structure.
 */
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
				      struct txentry_desc *txdesc,
				      struct ieee80211_tx_control *control);

/**
 * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
 * @entry: The entry which will be used to transfer the TX frame.
 * @txdesc: TX descriptor which will be used to write hardware descriptor
 *
 * This function will write a TX descriptor initialized by
 * &rt2x00queue_create_tx_descriptor to the hardware. After this call
 * has completed the frame is now owned by the hardware, the hardware
 * queue will have automatically be kicked unless this frame was generated
 * by rt2x00lib, in which case the frame is "special" and must be kicked
 * by the caller.
 */
void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
				     struct txentry_desc *txdesc);

/**
 * rt2x00queue_get_queue - Convert queue index to queue pointer
 * @rt2x00dev: Pointer to &struct rt2x00_dev.
@@ -963,13 +998,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
void rt2x00lib_rxdone(struct queue_entry *entry,
		      struct rxdone_entry_desc *rxdesc);

/*
 * TX descriptor initializer
 */
void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
			     struct sk_buff *skb,
			     struct ieee80211_tx_control *control);

/*
 * mac80211 handlers.
 */
+0 −148
Original line number Diff line number Diff line
@@ -611,154 +611,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);

/*
 * TX descriptor initializer
 */
void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
			     struct sk_buff *skb,
			     struct ieee80211_tx_control *control)
{
	struct txentry_desc txdesc;
	struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data;
	const struct rt2x00_rate *rate;
	int tx_rate;
	int length;
	int duration;
	int residual;
	u16 frame_control;
	u16 seq_ctrl;

	memset(&txdesc, 0, sizeof(txdesc));

	txdesc.queue = skbdesc->entry->queue->qid;
	txdesc.cw_min = skbdesc->entry->queue->cw_min;
	txdesc.cw_max = skbdesc->entry->queue->cw_max;
	txdesc.aifs = skbdesc->entry->queue->aifs;

	/*
	 * Read required fields from ieee80211 header.
	 */
	frame_control = le16_to_cpu(hdr->frame_control);
	seq_ctrl = le16_to_cpu(hdr->seq_ctrl);

	tx_rate = control->tx_rate->hw_value;

	/*
	 * Check whether this frame is to be acked
	 */
	if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
		__set_bit(ENTRY_TXD_ACK, &txdesc.flags);

	/*
	 * Check if this is a RTS/CTS frame
	 */
	if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
		__set_bit(ENTRY_TXD_BURST, &txdesc.flags);
		if (is_rts_frame(frame_control)) {
			__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags);
			__set_bit(ENTRY_TXD_ACK, &txdesc.flags);
		} else
			__clear_bit(ENTRY_TXD_ACK, &txdesc.flags);
		if (control->rts_cts_rate)
			tx_rate = control->rts_cts_rate->hw_value;
	}

	/*
	 * Determine retry information.
	 */
	txdesc.retry_limit = control->retry_limit;
	if (control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
		__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc.flags);

	/*
	 * Check if more fragments are pending
	 */
	if (ieee80211_get_morefrag(hdr)) {
		__set_bit(ENTRY_TXD_BURST, &txdesc.flags);
		__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags);
	}

	/*
	 * Beacons and probe responses require the tsf timestamp
	 * to be inserted into the frame.
	 */
	if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control))
		__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);

	/*
	 * Determine with what IFS priority this frame should be send.
	 * Set ifs to IFS_SIFS when the this is not the first fragment,
	 * or this fragment came after RTS/CTS.
	 */
	if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags)) {
		txdesc.ifs = IFS_SIFS;
	} else if (control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) {
		__set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc.flags);
		txdesc.ifs = IFS_BACKOFF;
	} else {
		txdesc.ifs = IFS_SIFS;
	}

	/*
	 * PLCP setup
	 * Length calculation depends on OFDM/CCK rate.
	 */
	rate = rt2x00_get_rate(tx_rate);
	txdesc.signal = rate->plcp;
	txdesc.service = 0x04;

	length = skbdesc->data_len + FCS_LEN;
	if (rate->flags & DEV_RATE_OFDM) {
		__set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags);

		txdesc.length_high = (length >> 6) & 0x3f;
		txdesc.length_low = length & 0x3f;
	} else {
		/*
		 * Convert length to microseconds.
		 */
		residual = get_duration_res(length, rate->bitrate);
		duration = get_duration(length, rate->bitrate);

		if (residual != 0) {
			duration++;

			/*
			 * Check if we need to set the Length Extension
			 */
			if (rate->bitrate == 110 && residual <= 30)
				txdesc.service |= 0x80;
		}

		txdesc.length_high = (duration >> 8) & 0xff;
		txdesc.length_low = duration & 0xff;

		/*
		 * When preamble is enabled we should set the
		 * preamble bit for the signal.
		 */
		if (rt2x00_get_rate_preamble(tx_rate))
			txdesc.signal |= 0x08;
	}

	rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc);

	/*
	 * Update queue entry.
	 */
	skbdesc->entry->skb = skb;

	/*
	 * The frame has been completely initialized and ready
	 * for sending to the device. The caller will push the
	 * frame to the device, but we are going to push the
	 * frame to debugfs here.
	 */
	rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, skb);
}
EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);

/*
 * Driver initialization handlers.
 */
Loading