Skip to contentSkip to conversation

rt2x00: Add guardian byte for beacons

PATCH In review Ivo van Doorn 1 participant 1 message Feb 28, 2007 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH 11/28 rt2x00: Add guardian byte for beacons

USB devices need a second entry in the beacon ring, the second entry is intended for the beacon data, but the first is a guardian byte that needs to be send first. Without that, there will be no beacon generation. And after the beacon generation has started, there is no need to update the beacon anymore the device will handle everything.

---

drivers/net/wireless/mac80211/rt2x00/rt2500usb.c +93 -22
index 49e70ca..1ea6696 100644
@@ -1751,18 +1751,30 @@ static void rt2500usb_beacondone(struct work_struct *work)
 {
 	struct data_ring *ring =
 		container_of(work, struct data_ring, irq_work);
-	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
-	struct data_entry *entry = rt2x00_get_data_entry(ring);
-	struct sk_buff *skb;
+	struct data_entry *entry;
 
-	skb = ieee80211_beacon_get(rt2x00dev->hw,
-		rt2x00dev->interface.id, &entry->tx_status.control);
-	if (!skb)
+	if (!GET_FLAG(ring->rt2x00dev, DEVICE_ENABLED_RADIO))
 		return;
 
-	rt2500usb_beacon_update(rt2x00dev->hw, skb, &entry->tx_status.control);
-
-	dev_kfree_skb_any(skb);
+	/*
+	 * Check if this was the guardian beacon,
+	 * if that was the case we need to send the real beacon now.
+	 * Otherwise we should free the sk_buffer, the device
+	 * should be doing the rest of the work now.
+	 */
+	if (ring->index == 1) {
+		rt2x00_ring_index_done_inc(ring);
+		entry = rt2x00_get_data_entry(ring);
+		usb_submit_urb(entry->priv, GFP_ATOMIC);
+		rt2x00_ring_index_inc(ring);
+	} else if (ring->index_done == 1) {
+		entry = rt2x00_get_data_entry_done(ring);
+		if (entry->skb) {
+			dev_kfree_skb(entry->skb);
+			entry->skb = NULL;
+		}
+		rt2x00_ring_index_done_inc(ring);
+	}
 }
 
 static void rt2500usb_rxdone(struct work_struct *work)
@@ -2401,9 +2413,11 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct usb_device *usb_dev =
 		interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
-	struct data_entry *entry;
-
-	entry = rt2x00_get_data_entry(&rt2x00dev->ring[RING_BEACON]);
+	struct data_ring *ring = &rt2x00dev->ring[RING_BEACON];
+	struct data_entry *beacon;
+	struct data_entry *guardian;
+	int length;
+	u16 reg;
 
 	/*
 	 * Just in case the ieee80211 doesn't set this,
@@ -2413,22 +2427,79 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
 	control->queue = IEEE80211_TX_QUEUE_BEACON;
 
 	/*
-	 * Update the beacon entry.
+	 * Obtain 2 entries, one for the guardian byte,
+	 * the second for the actual beacon.
 	 */
-	memcpy(rt2x00_txdata_addr(entry), skb->data, skb->len);
-	rt2500usb_write_tx_desc(rt2x00dev, rt2x00_txdesc_addr(entry),
-		(struct ieee80211_hdr *)skb->data, skb->len, control);
+	guardian = rt2x00_get_data_entry(ring);
+	rt2x00_ring_index_inc(ring);
+	beacon = rt2x00_get_data_entry(ring);
+
+	/*
+	 * First we create the beacon.
+	 */
+	skb_push(skb, ring->desc_size);
+	rt2500usb_write_tx_desc(rt2x00dev,
+		(struct data_desc*)skb->data,
+		(struct ieee80211_hdr*)(skb->data + ring->desc_size),
+		skb->len - ring->desc_size,
+		control);
+
+	/*
+	 * Length passed to usb_fill_urb cannot be an odd number,
+	 * so add 1 byte to make it even.
+	 */
+	length = skb->len;
+	if (length % 2)
+		length++;
 
-	SET_FLAG(entry, ENTRY_OWNER_NIC);
 	usb_fill_bulk_urb(
-		rt2x00_urb(entry),
+		beacon->priv,
 		usb_dev,
 		usb_sndbulkpipe(usb_dev, 1),
-		entry->data_addr,
-		skb->len + rt2x00dev->ring[RING_BEACON].desc_size,
+		skb->data,
+		length,
 		rt2500usb_interrupt,
-		entry);
-	usb_submit_urb(rt2x00_urb(entry), GFP_ATOMIC);
+		beacon);
+
+	beacon->skb = skb;
+
+	/*
+	 * Second we need to create the guardian byte.
+	 * We only need a single byte, so lets recycle
+	 * the 'flags' field we are not using for beacons.
+	 */
+	guardian->reg = 0;
+	usb_fill_bulk_urb(
+		guardian->priv,
+		usb_dev,
+		usb_sndbulkpipe(usb_dev, 1),
+		&guardian->reg,
+		1,
+		rt2500usb_interrupt,
+		guardian);
+
+	/*
+	 * Send out the guardian byte.
+	 */
+	usb_submit_urb(guardian->priv, GFP_ATOMIC);
+
+	/*
+	 * Enable beacon generation.
+	 */
+	rt2x00_register_read(rt2x00dev, TXRX_CSR19, &reg);
+	if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
+		rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+		/*
+		 * Beacon generation will fail initially.
+		 * To prevent this we need to register the TXRX_CSR19
+		 * register several times.
+		 */
+		rt2x00_register_write(rt2x00dev, TXRX_CSR19, reg);
+		rt2x00_register_write(rt2x00dev, TXRX_CSR19, 0);
+		rt2x00_register_write(rt2x00dev, TXRX_CSR19, reg);
+		rt2x00_register_write(rt2x00dev, TXRX_CSR19, 0);
+		rt2x00_register_write(rt2x00dev, TXRX_CSR19, reg);
+	}
 
 	return 0;
 }
drivers/net/wireless/mac80211/rt2x00/rt2x00.h +5 -0
index d6e968c..b79f860 100644
@@ -525,6 +525,11 @@ struct data_entry {
 #define ENTRY_RTS_CTS_FRAME	0x00000002
 
 	/*
+	 * extra register field
+	 */
+	unsigned int reg;
+
+	/*
 	 * Ring we belong to.
 	 */
 	struct data_ring *ring;
drivers/net/wireless/mac80211/rt2x00/rt2x00usb.h +6 -0
index a0dc726..b4f2961 100644
@@ -78,4 +78,10 @@
  */
 #define LINK_TUNE_INTERVAL	( 1 * HZ )
 
+/*
+ * USB devices need an additional Beacon (guardian beacon) to be generated.
+ */
+#undef BEACON_ENTRIES
+#define BEACON_ENTRIES 2
+
 #endif /* RT2X00USB_H */
drivers/net/wireless/mac80211/rt2x00/rt73usb.c +84 -23

134 lines not on this page · raw message