Skip to content

RFC p54: various updates (all in one)

Chr linux-wireless 1 version New

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 RFC Latest0 of 4 patches 0 repliesNew

Patches in v1 No applies recorded yet

None of the 4 patches the cover letter announces are in this archive.

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

Cover letter [RFC][PATCH 0/4] p54: various updates (all in one)

Give it a good testing!

Notes:
- IBSS mode is maybe a buggy, but it'll take another semester break to figure out whats wrong with the TSF timer.

- Powersaving package queueing is disabled in AP-Mode. As my Intel 4965N won't reconnect with it. (but the atheros card does?!)

BTW:
since no one has the codebase to p54/, or made any other changes I made the (all-in-on) diff against the (old) kernel-code... but with the _new_ path!

if you want to test it, don't forget the mac80211 patch!
http://article.gmane.org/gmane.linux.kernel.wireless.general/13115

Regards,
Chr.

drivers/net/wireless/p54/p54common.c +444 -91
diff -Nurp a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
@@ -3,7 +3,7 @@
  * Common code for mac80211 Prism54 drivers
  *
  * Copyright (c) 2006, Michael Wu <[email protected]>
- * Copyright (c) 2007, Christian Lamparter <[email protected]>
+ * Copyright (c) 2007, 2008, Christian Lamparter <[email protected]>
  *
  * Based on the islsm (softmac prism54) driver, which is:
  * Copyright 2004-2006 Jean-Baptiste Note <[email protected]>, et al.
@@ -25,7 +25,7 @@
 MODULE_AUTHOR("Michael Wu <[email protected]>");
 MODULE_DESCRIPTION("Softmac Prism54 common code");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
+MODULE_ALIAS("p54common");
 
 static struct ieee80211_rate p54_rates[] = {
 	{ .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
@@ -66,7 +66,6 @@ static struct ieee80211_supported_band b
 	.n_bitrates = ARRAY_SIZE(p54_rates),
 };
 
-
 void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 {
 	struct p54_common *priv = dev->priv;
@@ -146,10 +145,10 @@ void p54_parse_firmware(struct ieee80211
 
 	if (priv->fw_var >= 0x300) {
 		/* Firmware supports QoS, use it! */
-		priv->tx_stats.data[0].limit = 3;
-		priv->tx_stats.data[1].limit = 4;
-		priv->tx_stats.data[2].limit = 3;
-		priv->tx_stats.data[3].limit = 1;
+		priv->tx_stats[4].limit = 3;
+		priv->tx_stats[5].limit = 4;
+		priv->tx_stats[6].limit = 3;
+		priv->tx_stats[7].limit = 1;
 		dev->queues = 4;
 	}
 }
@@ -297,10 +296,6 @@ int p54_parse_eeprom(struct ieee80211_hw
 			/* make it overrun */
 			entry_len = len;
 			break;
-		default:
-			printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
-				le16_to_cpu(entry->code));
-			break;
 		}
 
 		entry = (void *)entry + (entry_len + 1)*2;
@@ -335,6 +330,11 @@ int p54_parse_eeprom(struct ieee80211_hw
 }
 EXPORT_SYMBOL_GPL(p54_parse_eeprom);
 
+static inline int p54_rssi_to_dbm(u8 rssi)
+{
+	return rssi / 2 - 100;
+}
+
 void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
 {
 	struct p54_eeprom_lm86 *eeprom_hdr;
@@ -349,16 +349,28 @@ void p54_fill_eeprom_readback(struct p54
 }
 EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
 
-static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
+static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
+	struct p54_common *priv = dev->priv;
 	struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
 	struct ieee80211_rx_status rx_status = {0};
-	u16 freq = le16_to_cpu(hdr->freq);
 
-	rx_status.ssi = hdr->rssi;
-	/* XX correct? */
+	if (!(hdr->magic & cpu_to_le16(0x01))) {
+		if (priv->rx_filter == P54_RX_FILTER_FCSFAIL)
+			rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+		else
+			/* reuse skb */
+			return 0;
+	}
+	rx_status.ssi = p54_rssi_to_dbm(hdr->rssi);
+	rx_status.noise = priv->stats.noise_floor;
+	if (rx_status.ssi > rx_status.noise)
+		rx_status.signal = rx_status.ssi - rx_status.noise;
+
+	/* FIX MAC80211: for now we remove the short preamble flag */
 	rx_status.rate_idx = hdr->rate & 0xf;
-	rx_status.freq = freq;
+
+	rx_status.freq = le16_to_cpu(hdr->freq);
 	rx_status.band = IEEE80211_BAND_2GHZ;
 	rx_status.antenna = hdr->antenna;
 	rx_status.mactime = le64_to_cpu(hdr->timestamp);
@@ -368,6 +380,8 @@ static void p54_rx_data(struct ieee80211
 	skb_trim(skb, le16_to_cpu(hdr->len));
 
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+	return -1;
 }
 
 static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
@@ -379,7 +393,7 @@ static void inline p54_wake_free_queues(
 	 * But, what if some are full? */
 
 	for (i = 0; i < dev->queues; i++)
-		if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+		if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit)
 			ieee80211_wake_queue(dev, i);
 }
 
@@ -388,12 +402,15 @@ static void p54_rx_frame_sent(struct iee
 	struct p54_common *priv = dev->priv;
 	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
 	struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
-	struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
+	struct sk_buff *entry;
+	unsigned long flags;
 	u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
 	struct memrecord *range = NULL;
 	u32 freed = 0;
 	u32 last_addr = priv->rx_start;
 
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+	entry = (struct sk_buff *) priv->tx_queue.next;
 	while (entry != (struct sk_buff *)&priv->tx_queue) {
 		range = (struct memrecord *)&entry->cb;
 		if (range->start_addr == addr) {
@@ -409,42 +426,68 @@ static void p54_rx_frame_sent(struct iee
 
 			last_addr = range->end_addr;
 			__skb_unlink(entry, &priv->tx_queue);
+			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
 			if (!range->control) {
 				kfree_skb(entry);
-				break;
+				goto out;
 			}
 			memset(&status, 0, sizeof(status));
 			memcpy(&status.control, range->control,
 			       sizeof(status.control));
 			kfree(range->control);
-			priv->tx_stats.data[status.control.queue].len--;
 
 			entry_hdr = (struct p54_control_hdr *) entry->data;
 			entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
+			priv->tx_stats[entry_data->frame_type].len--;
+
 			if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
 				pad = entry_data->align[0];
 
 			if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
 				if (!(payload->status & 0x01))
 					status.flags |= IEEE80211_TX_STATUS_ACK;
-				else
-					status.excessive_retries = 1;
+				else {
+					if ((payload->status & 0x04) && 
+					   (priv->mode == IEEE80211_IF_TYPE_AP))
+						status.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+					else
+						status.excessive_retries = 1;
+				}
 			}
 			status.retry_count = payload->retries - 1;
 			status.ack_signal = le16_to_cpu(payload->ack_rssi);
 			skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
 			ieee80211_tx_status_irqsafe(dev, entry, &status);
-			break;
+			goto out;
 		} else
 			last_addr = range->end_addr;
 		entry = entry->next;
 	}
 
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+out:
 	if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
 	    sizeof(struct p54_control_hdr))
 		p54_wake_free_queues(dev);
 }
 
+static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_statistics *hw_stats = (struct p54_statistics *)hdr->data;
+
+	priv->stats.rx_success = le32_to_cpu(hw_stats->rx_success);
+	priv->stats.rx_errors = le32_to_cpu(hw_stats->rx_errors);
+	priv->stats.rx_aborts = le32_to_cpu(hw_stats->rx_aborts);
+	priv->stats.rx_aborts_phy = le32_to_cpu(hw_stats->rx_aborts_phy);
+	priv->stats.rx_rts_success = le32_to_cpu(hw_stats->rx_rts_success);
+	priv->stats.rx_rts_failed = le32_to_cpu(hw_stats->rx_rts_failed);
+	priv->stats.noise_floor = p54_rssi_to_dbm(hw_stats->noise_floor);
+	priv->stats.tsf = le32_to_cpu(hw_stats->tsf);
+}
+
 static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
@@ -453,6 +496,9 @@ static void p54_rx_control(struct ieee80
 	case P54_CONTROL_TYPE_TXDONE:
 		p54_rx_frame_sent(dev, skb);
 		break;
+	case P54_CONTROL_TYPE_STAT_READBACK:
+		p54_rx_stats(dev, skb);
+		break;
 	case P54_CONTROL_TYPE_BBP:
 		break;
 	default:
@@ -469,8 +515,7 @@ int p54_rx(struct ieee80211_hw *dev, str
 	switch (type) {
 	case 0x00:
 	case 0x01:
-		p54_rx_data(dev, skb);
-		return -1;
+		return p54_rx_data(dev, skb);
 	case 0x4d:
 		/* TODO: do something better... but then again, I've never seen this happen */
 		printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
@@ -552,6 +597,67 @@ static void p54_assign_address(struct ie
 	data->req_id = cpu_to_le32(target_addr + 0x70);
 }
 
+#ifndef WLAN_FC_GET_TYPE
+#define WLAN_FC_GET_TYPE(fc) (fc & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) (fc & IEEE80211_FCTL_STYPE)
+#endif
+
+static int p54_tx_fill_header(struct ieee80211_hw *dev, struct ieee80211_hdr *hdr,
+	struct ieee80211_tx_control *control, u8 *retry1, u8 *retry2,
+	u8 *frame_type, u16 *magic, u16 *aid)
+{
+	struct p54_common *priv = dev->priv;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	if (!(control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
+	   IEEE80211_TXCTL_USE_CTS_PROTECT)))
+		*magic = 0x10;
+	else	
+		*magic = 0;
+	
+	*retry1 = *retry2 = control->retry_limit;
+
+	if ((control->flags & IEEE80211_TXCTL_NO_ACK))
+		*aid = 0;
+	else {
+		if (control->aid) 
+			*aid = control->aid + 1;
+		else
+			*aid = 1;
+	}
+
+	/* TODO: enable powersaving package queueing in AP-Mode */
+	if (priv->mode == IEEE80211_IF_TYPE_AP)
+		*magic |= 0x20;
+
+	if (unlikely(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT))
+		switch (WLAN_FC_GET_STYPE(fc)) {
+		case IEEE80211_STYPE_PROBE_REQ:
+			*aid = 0;
+			*magic |= 0x20;
+			*frame_type = 1;
+			return 0;
+		case IEEE80211_STYPE_BEACON:
+			*aid = 0;
+			*retry2 = *retry1 = 1;
+			*frame_type = 0;
+			*magic = 0x02; /* tell the FW to fill in the TSF */
+			return 0;
+		case IEEE80211_STYPE_PROBE_RESP:
+			*magic |= 0x02;
+			*aid = 0;
+			*frame_type = 2;
+			return 0;
+		default:
+			*frame_type = 2;
+			return 0;
+		}	
+	else
+		*frame_type = control->queue + 4;
+
+	return 1;
+}
+
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
 		  struct ieee80211_tx_control *control)
 {
@@ -560,16 +666,26 @@ static int p54_tx(struct ieee80211_hw *d
 	struct p54_control_hdr *hdr;
 	struct p54_tx_control_allocdata *txhdr;
 	struct ieee80211_tx_control *control_copy;
+	struct ieee80211_hdr *ieeehdr = (struct ieee80211_hdr *)skb->data;
 	size_t padding, len;
-	u8 rate;
+	u16 aid, magic;
+	u8 rate, retry1, retry2, frame_type;
 
-	current_queue = &priv->tx_stats.data[control->queue];
-	if (unlikely(current_queue->len > current_queue->limit))
-		return NETDEV_TX_BUSY;
-	current_queue->len++;
-	current_queue->count++;
-	if (current_queue->len == current_queue->limit)
-		ieee80211_stop_queue(dev, control->queue);
+	if (p54_tx_fill_header(dev, ieeehdr, control, &retry1, &retry2, 
+			       &frame_type, &magic, &aid)) {
+
+		current_queue = &priv->tx_stats[frame_type];
+		if (unlikely(current_queue->len > current_queue->limit))
+			return NETDEV_TX_BUSY;
+		current_queue->len++;
+		current_queue->count++;
+		if (current_queue->len == current_queue->limit)
+			ieee80211_stop_queue(dev, control->queue);
+	} else {
+		current_queue = &priv->tx_stats[frame_type];
+		current_queue->len++;
+		current_queue->count++;
+	}
 
 	padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
 	len = skb->len;
@@ -583,36 +699,38 @@ static int p54_tx(struct ieee80211_hw *d
 	hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
 
 	if (padding)
-		hdr->magic1 = cpu_to_le16(0x4010);
-	else
-		hdr->magic1 = cpu_to_le16(0x0010);
+		magic |= 0x4000;
+	
+	hdr->magic1 = cpu_to_le16(magic);
 	hdr->len = cpu_to_le16(len);
-	hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
-	hdr->retry1 = hdr->retry2 = control->retry_limit;
+	hdr->type = cpu_to_le16(aid);
+	hdr->retry1 = retry1;
+	hdr->retry2 = retry2;
 	p54_assign_address(dev, skb, hdr, skb->len, control_copy);
 
-	memset(txhdr->wep_key, 0x0, 16);
-	txhdr->padding = 0;
-	txhdr->padding2 = 0;
-
 	/* TODO: add support for alternate retry TX rates */
 	rate = control->tx_rate->hw_value;
 	if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
 		rate |= 0x10;
-	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+	else if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
 		rate |= 0x40;
 	else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		rate |= 0x20;
 	memset(txhdr->rateset, rate, 8);
-	txhdr->wep_key_present = 0;
-	txhdr->wep_key_len = 0;
-	txhdr->frame_type = cpu_to_le32(control->queue + 4);
-	txhdr->magic4 = 0;
+	txhdr->key_type = 0;
+	txhdr->key_len = 0;
+	txhdr->frame_type = frame_type;
 	txhdr->antenna = (control->antenna_sel_tx == 0) ?
 		2 : control->antenna_sel_tx - 1;
-	txhdr->output_power = 0x7f; // HW Maximum
-	txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
-		0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
+	txhdr->output_power = 0x7f; /* 0.25 dbm / unit */
+	if (control->rts_cts_rate)
+		txhdr->cts_rate = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+			0 : (control->rts_cts_rate->hw_value | 0x20 |
+			    (rate & 0x10));
+	else
+		txhdr->cts_rate = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+			0 : (0x23 | (rate & 0x10));
+
 	if (padding)
 		txhdr->align[0] = padding;
 
@@ -620,9 +738,36 @@ static int p54_tx(struct ieee80211_hw *d
 	return 0;
 }
 
-static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
-			  const u8 *dst, const u8 *src, u8 antenna,
-			  u32 magic3, u32 magic8, u32 magic9)
+int __p54_set_tim(struct ieee80211_hw *dev, u16 aid, int set)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_tim *tim;
+
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*tim) +
+		      priv->tx_hdr_len, GFP_ATOMIC);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*tim));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_TIM);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*tim), NULL);
+
+	tim = (struct p54_tx_control_tim *) hdr->data;
+	tim->count = 1;	/* just one entry */
+	tim->entry[0] = set ? cpu_to_le16(aid | 0x8000) : cpu_to_le16(aid);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*tim), 1);
+
+	return 0;
+}
+
+const static unsigned char p54_client_rts_rates[8] = { 8, 6, 4, 1, 0, 0, 0, 0 };
+const static unsigned char p54_ap_rts_rates[8] = { 3, 3, 1, 0, 0, 0, 0, 0 };
+
+static int p54_set_filter(struct ieee80211_hw *dev, u8 filter_type)
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_control_hdr *hdr;
@@ -641,24 +786,68 @@ static int p54_set_filter(struct ieee802
 	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
 	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
 
-	filter->filter_type = cpu_to_le16(filter_type);
-	memcpy(filter->dst, dst, ETH_ALEN);
-	if (!src)
-		memset(filter->src, ~0, ETH_ALEN);
+	filter->filter_type = filter_type;
+	memcpy(filter->our_mac, priv->mac_addr, ETH_ALEN);
+
+	/* 0x15F is a bitrate mask
+	 * = 0000000101011111b
+	 * = 24MBits 12MBits 6MBit 11MBit 5.5MBits 2MBits 1Mbit */
+	filter->bss_basic_rates = cpu_to_le32(0x15F);
+	memset(filter->bss_filter_mac, ~0, ETH_ALEN);
+
+	if (filter_type == P54_FILTER_TYPE_AP)
+		memcpy(filter->rts_rates, p54_ap_rts_rates, 8);
 	else
-		memcpy(filter->src, src, ETH_ALEN);
-	filter->antenna = antenna;
-	filter->magic3 = cpu_to_le32(magic3);
+		memcpy(filter->rts_rates, p54_client_rts_rates, 8);
+
+	filter->rx_antenna = (dev->conf.antenna_sel_rx == 0) ? 2 :
+		dev->conf.antenna_sel_rx - 1;
 	filter->rx_addr = cpu_to_le32(priv->rx_end);
 	filter->max_rx = cpu_to_le16(0x0620);	/* FIXME: for usb ver 1.. maybe */
 	filter->rxhw = priv->rxhw;
-	filter->magic8 = cpu_to_le16(magic8);
-	filter->magic9 = cpu_to_le16(magic9);
+
+	/* that's beacon_int * dtim_period * 5, unless
+	 * there's a way to get these values here, let's
+	 * use the standard ones */
+	filter->dtim_timer = cpu_to_le16(dev->conf.beacon_int * 1 * 5);
 
 	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
 	return 0;
 }
 
+static int p54_init_misc(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_misc *misc;
+
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*misc) +
+		      priv->tx_hdr_len, GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*misc));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_MISCINIT);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*misc), NULL);
+
+	misc = (struct p54_tx_control_misc *) hdr->data;
+
+	misc->flags = cpu_to_le16(0);
+	misc->entry[1] = cpu_to_le16(1000);
+	misc->entry[3] = cpu_to_le16(1000);
+	misc->entry[5] = cpu_to_le16(1000);
+	misc->entry[7] = cpu_to_le16(1000);
+
+	misc->flag2 = cpu_to_le16(1);
+	misc->flag3 = misc->data = 0;
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*misc), 1);
+
+	return 0;
+}
+
 static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
 {
 	struct p54_common *priv = dev->priv;
@@ -811,8 +1000,8 @@ static void p54_set_vdcf(struct ieee8021
 
 	if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
 		vdcf->slottime = 9;
-		vdcf->magic1 = 0x00;
-		vdcf->magic2 = 0x10;
+		vdcf->magic1 = 0x10;
+		vdcf->magic2 = 0x00;
 	} else {
 		vdcf->slottime = 20;
 		vdcf->magic1 = 0x0a;
@@ -861,6 +1050,8 @@ static int p54_add_interface(struct ieee
 
 	switch (conf->type) {
 	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_AP:
+	case IEEE80211_IF_TYPE_IBSS:
 		priv->mode = conf->type;
 		break;
 	default:
@@ -869,20 +1060,29 @@ static int p54_add_interface(struct ieee
 
 	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
+	p54_set_filter(dev, P54_FILTER_TYPE_NONE);
 
 	switch (conf->type) {
 	case IEEE80211_IF_TYPE_STA:
-		p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
+		priv->filter_type = P54_FILTER_TYPE_STA;
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		priv->filter_type = P54_FILTER_TYPE_AP;
+		break;
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->filter_type = P54_FILTER_TYPE_ADHOC;
 		break;
 	default:
 		BUG();	/* impossible */
 		break;
 	}
 
+	p54_init_misc(dev);
 	p54_set_leds(dev, 1, 0, 0);
 
+	/* start statistics readback timer */
+	mod_timer(&priv->stats.timer, jiffies + HZ);
+
 	return 0;
 }
 
@@ -890,9 +1090,15 @@ static void p54_remove_interface(struct 
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
+
+	del_timer(&priv->stats.timer);
+	if (priv->mode == P54_FILTER_TYPE_AP)
+		__p54_set_tim(dev, 0, 0);
+
 	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->filter_type = P54_FILTER_TYPE_NONE;
 	memset(priv->mac_addr, 0, ETH_ALEN);
-	p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
+	p54_set_filter(dev, P54_FILTER_TYPE_NONE);
 }
 
 static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -904,16 +1110,90 @@ static int p54_config(struct ieee80211_h
 	return ret;
 }
 
+static void p54_beacon_tim(struct sk_buff *skb)
+{
+	/*
+	 * the TIM MUST be at the end of the beacon frame,
+	 * because it'll be overwritten!
+	 */
+
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	u8 *pos, *end;
+
+	if (skb->len <= sizeof(mgmt))
+		return ;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = skb->data + skb->len;
+	while (pos < end) {
+		if (pos + 2 + pos[1] > end) {
+			printk(KERN_ERR "p54: parsing beacon failed\n");
+			return;
+		}
+
+		if (pos[0] == WLAN_EID_TIM) {
+			u8 dtim_len = pos[1];
+			u8 dtim_period;
+			u8 *next = pos + 2 + dtim_len;
+
+			/* mac80211 sets it atleast to 4... */
+			if (dtim_len < 3)
+				return ;
+
+			dtim_period = pos[3];
+			memmove(pos, next, end - next);
+		        skb_trim(skb, skb->len - (dtim_len - 3));
+			pos = end - (dtim_len + 2);
+
+			/* add a dummy at the end */
+			pos[0] = WLAN_EID_TIM;
+			pos[1] = 3;
+			pos[2] = 0;
+			pos[3] = dtim_period;
+			pos[4] = 0;
+			return ;
+		}
+		pos += 2 + pos[1];
+	}
+}
+
+static int p54_beacon_update(struct ieee80211_hw *dev,
+			     struct sk_buff *skb,
+			     struct ieee80211_tx_control *control)
+{
+	struct p54_common *priv = dev->priv;
+
+	p54_set_freq(dev, dev->conf.channel->center_freq);
+	p54_set_filter(dev, priv->filter_type);
+	p54_beacon_tim(skb);
+	p54_tx(dev, skb, control);
+	p54_set_vdcf(dev);
+	p54_set_leds(dev, 1, 1, 0);
+
+	return 0;
+}
+
 static int p54_config_interface(struct ieee80211_hw *dev,
 				struct ieee80211_vif *vif,
 				struct ieee80211_if_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
 
-	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
-	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
-	p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
-	memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+		p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		if (conf->beacon && conf->beacon_control)
+			return p54_beacon_update(dev, conf->beacon,
+						 conf->beacon_control);
+		__p54_set_tim(dev, 0, 0);
+		break;
+	}
+
+	p54_set_filter(dev, priv->filter_type);
+
 	return 0;
 }
 
@@ -923,16 +1203,34 @@ static void p54_configure_filter(struct 
 				 int mc_count, struct dev_mc_list *mclist)
 {
 	struct p54_common *priv = dev->priv;
+	unsigned flags = FIF_BCN_PRBRESP_PROMISC | FIF_PROMISC_IN_BSS;
+
+	if (priv->filter_type & P54_FILTER_TYPE_PROMISC)
+		flags |= FIF_FCSFAIL;
 
-	*total_flags &= FIF_BCN_PRBRESP_PROMISC;
+	*total_flags &= flags;
 
 	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
 		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-			p54_set_filter(dev, 0, priv->mac_addr,
-				       NULL, 2, 0, 0, 0);
+			p54_set_filter(dev, P54_FILTER_TYPE_NONE);
+		else
+			p54_set_filter(dev, priv->filter_type);
+	}
+
+	if (changed_flags & FIF_PROMISC_IN_BSS) {
+		if (*total_flags & FIF_PROMISC_IN_BSS)
+			priv->filter_type |= P54_FILTER_TYPE_PROMISC;
+		else
+			priv->filter_type &= ~P54_FILTER_TYPE_PROMISC;
+
+		p54_set_filter(dev, priv->filter_type);
+	}
+
+	if (changed_flags & FIF_FCSFAIL) {
+		if (*total_flags & FIF_FCSFAIL)
+			priv->rx_filter |= P54_RX_FILTER_FCSFAIL;
 		else
-			p54_set_filter(dev, 0, priv->mac_addr,
-				       priv->bssid, 2, 0, 0, 0);
+			priv->rx_filter &= ~P54_RX_FILTER_FCSFAIL;
 	}
 }
 
@@ -956,10 +1254,38 @@ static int p54_conf_tx(struct ieee80211_
 	return 0;
 }
 
+static void p54_stats_timer(unsigned long data)
+{
+	struct ieee80211_hw *dev = (struct ieee80211_hw *)data;
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_statistics *stat;
+
+	hdr = (void *)priv->stats.cached_stats + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8000);
+	hdr->len = cpu_to_le16(sizeof(*stat));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK);
+	hdr->retry1 = hdr->retry2 = 0;
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stat), NULL);
+
+	stat = (struct p54_statistics *)hdr->data;
+	memset(stat, 0x0, sizeof(*stat));
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stat), 0);
+
+	/* get stats every 5 seconds */
+	mod_timer(&priv->stats.timer, jiffies + 5*HZ);
+}
+
 static int p54_get_stats(struct ieee80211_hw *dev,
 			 struct ieee80211_low_level_stats *stats)
 {
-	/* TODO */
+	struct p54_common *priv = dev->priv;
+
+	stats->dot11RTSFailureCount = priv->stats.rx_rts_failed;
+	stats->dot11RTSSuccessCount = priv->stats.rx_rts_success;
+	stats->dot11FCSErrorCount = priv->stats.rx_errors;
+
 	return 0;
 }
 
@@ -967,11 +1293,19 @@ static int p54_get_tx_stats(struct ieee8
 			    struct ieee80211_tx_queue_stats *stats)
 {
 	struct p54_common *priv = dev->priv;
-	unsigned int i;
 
-	for (i = 0; i < dev->queues; i++)
-		memcpy(&stats->data[i], &priv->tx_stats.data[i],
-			sizeof(stats->data[i]));
+	memcpy(&stats->data, &priv->tx_stats[4],
+			sizeof(stats->data[0]) * dev->queues);
+
+	return 0;
+}
+
+
+int p54_set_tim(struct ieee80211_hw *dev, int aid, int set)
+{
+	/* AID 1 is reserved */
+
+	__p54_set_tim(dev, (u16)aid + 1, set);
 
 	return 0;
 }
@@ -986,6 +1320,8 @@ static const struct ieee80211_ops p54_op
 	.config_interface	= p54_config_interface,
 	.configure_filter	= p54_configure_filter,
 	.conf_tx		= p54_conf_tx,
+	.set_tim		= p54_set_tim,
+	.beacon_update		= p54_beacon_update,
 	.get_stats		= p54_get_stats,
 	.get_tx_stats		= p54_get_tx_stats
 };
@@ -1003,25 +1339,41 @@ struct ieee80211_hw *p54_init_common(siz
 	priv->mode = IEEE80211_IF_TYPE_INVALID;
 	skb_queue_head_init(&priv->tx_queue);
 	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
-	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
-		    IEEE80211_HW_RX_INCLUDES_FCS;
-	dev->channel_change_time = 1000;	/* TODO: find actual value */
-	dev->max_rssi = 127;
-
-	priv->tx_stats.data[0].limit = 5;
+	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		     IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+		     IEEE80211_HW_RX_INCLUDES_FCS;
+
+	dev->channel_change_time = 5000;
+	priv->stats.noise_floor = -93;
+	dev->max_signal = 64;
+	dev->max_rssi = -36;
+	dev->max_noise = -36;
+
+	priv->tx_stats[0].limit = 1; /* beacon queue */
+	priv->tx_stats[1].limit = 1; /* broadcasts / probes (passive scan)*/
+	priv->tx_stats[2].limit = 1; /* management frame queue */
+	priv->tx_stats[3].limit = 1; /* used to be the data queue */
+	priv->tx_stats[4].limit = 5; /* data queue */
+	priv->filter_type = P54_FILTER_TYPE_NONE;
+	priv->rx_filter = P54_RX_FILTER_NOTHING;
 	dev->queues = 1;
 
 	dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
 				 sizeof(struct p54_tx_control_allocdata);
 
         priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) +
-              priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
-
-	if (!priv->cached_vdcf) {
+		priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
+	priv->stats.cached_stats = kzalloc(sizeof(struct p54_statistics) +
+		priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
+
+	if (!priv->cached_vdcf || !priv->stats.cached_stats) {
+		kfree(priv->cached_vdcf);
+		kfree(priv->stats.cached_stats);
 		ieee80211_free_hw(dev);
 		return NULL;
 	}
 
+	setup_timer(&priv->stats.timer, p54_stats_timer, (unsigned long)dev);
 	p54_init_vdcf(dev);
 
 	return dev;
@@ -1035,6 +1387,7 @@ void p54_free_common(struct ieee80211_hw
 	kfree(priv->output_limit);
 	kfree(priv->curve_data);
 	kfree(priv->cached_vdcf);
+	kfree(priv->stats.cached_stats);
 }
 EXPORT_SYMBOL_GPL(p54_free_common);
 
drivers/net/wireless/p54/p54common.h +81 -26

166 lines not on this page · raw message

drivers/net/wireless/p54/p54.h +37 -6

86 lines not on this page · raw message

drivers/net/wireless/p54/p54pci.c +193 -107

491 lines not on this page · raw message

drivers/net/wireless/p54/p54pci.h +14 -9
diff -Nurp a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54PCI_H
-#define PRISM54PCI_H
+#ifndef P54PCI_H
+#define P54PCI_H
 
 /*
  * Defines for PCI based mac80211 Prism54 driver
@@ -68,7 +68,7 @@ struct p54p_csr {
 } __attribute__ ((packed));
 
 /* usb backend only needs the register defines above */
-#ifndef PRISM54USB_H
+#ifndef P54USB_H
 struct p54p_desc {
 	__le32 host_addr;
 	__le32 device_addr;
@@ -92,15 +92,20 @@ struct p54p_priv {
 	struct p54_common common;
 	struct pci_dev *pdev;
 	struct p54p_csr __iomem *map;
+	struct tasklet_struct rx_tasklet;
 
-	spinlock_t lock;
+	spinlock_t tx_lock;
+	spinlock_t rx_lock;
 	struct p54p_ring_control *ring_control;
 	dma_addr_t ring_control_dma;
-	u32 rx_idx, tx_idx;
-	struct sk_buff *rx_buf[8];
-	void *tx_buf[32];
+	u32 rx_idx_data, tx_idx_data;
+	u32 rx_idx_mgmt, tx_idx_mgmt;
+	struct sk_buff *rx_buf_data[8];
+	struct sk_buff *rx_buf_mgmt[4];
+	void *tx_buf_data[32];
+	void *tx_buf_mgmt[4];
 	struct completion boot_comp;
 };
 
-#endif /* PRISM54USB_H */
-#endif /* PRISM54PCI_H */
+#endif /* P54USB_H */
+#endif /* P54PCI_H */
drivers/net/wireless/p54/p54usb.c +17 -17
diff -Nurp a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
@@ -27,7 +27,7 @@
 MODULE_AUTHOR("Michael Wu <[email protected]>");
 MODULE_DESCRIPTION("Prism54 USB wireless driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54usb");
+MODULE_ALIAS("p54usb");
 
 static struct usb_device_id p54u_table[] __devinitdata = {
 	/* Version 1 devices (pci chip + net2280) */
@@ -311,7 +311,7 @@ static int p54u_read_eeprom(struct ieee8
 
 	buf = kmalloc(0x2020, GFP_KERNEL);
 	if (!buf) {
-		printk(KERN_ERR "prism54usb: cannot allocate memory for "
+		printk(KERN_ERR "p54usb: cannot allocate memory for "
 		       "eeprom readback!\n");
 		return -ENOMEM;
 	}
@@ -320,7 +320,7 @@ static int p54u_read_eeprom(struct ieee8
 		*((u32 *) buf) = priv->common.rx_start;
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
 		if (err) {
-			printk(KERN_ERR "prism54usb: addr send failed\n");
+			printk(KERN_ERR "p54usb: addr send failed\n");
 			goto fail;
 		}
 	} else {
@@ -330,7 +330,7 @@ static int p54u_read_eeprom(struct ieee8
 		reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
 		err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
 		if (err) {
-			printk(KERN_ERR "prism54usb: dev_int send failed\n");
+			printk(KERN_ERR "p54usb: dev_int send failed\n");
 			goto fail;
 		}
 	}
@@ -348,7 +348,7 @@ static int p54u_read_eeprom(struct ieee8
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
 			    EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
 	if (err) {
-		printk(KERN_ERR "prism54usb: eeprom req send failed\n");
+		printk(KERN_ERR "p54usb: eeprom req send failed\n");
 		goto fail;
 	}
 
@@ -358,7 +358,7 @@ static int p54u_read_eeprom(struct ieee8
 	if (!err && alen > offset) {
 		p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
 	} else {
-		printk(KERN_ERR "prism54usb: eeprom read failed!\n");
+		printk(KERN_ERR "p54usb: eeprom read failed!\n");
 		err = -EINVAL;
 		goto fail;
 	}
@@ -446,7 +446,7 @@ static int p54u_upload_firmware_3887(str
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
 		if (err) {
-			printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+			printk(KERN_ERR "p54usb: firmware upload failed!\n");
 			goto err_upload_failed;
 		}
 
@@ -457,7 +457,7 @@ static int p54u_upload_firmware_3887(str
 	*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
 	if (err) {
-		printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+		printk(KERN_ERR "p54usb: firmware upload failed!\n");
 		goto err_upload_failed;
 	}
 
@@ -468,13 +468,13 @@ static int p54u_upload_firmware_3887(str
 			break;
 
 		if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
-			printk(KERN_INFO "prism54usb: firmware upload failed!\n");
+			printk(KERN_INFO "p54usb: firmware upload failed!\n");
 			err = -EINVAL;
 			break;
 		}
 
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "prism54usb: firmware boot timed out!\n");
+			printk(KERN_ERR "p54usb: firmware boot timed out!\n");
 			err = -ETIMEDOUT;
 			break;
 		}
@@ -486,7 +486,7 @@ static int p54u_upload_firmware_3887(str
 	buf[1] = '\r';
 	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
 	if (err) {
-		printk(KERN_ERR "prism54usb: firmware boot failed!\n");
+		printk(KERN_ERR "p54usb: firmware boot failed!\n");
 		goto err_upload_failed;
 	}
 
@@ -648,7 +648,7 @@ static int p54u_upload_firmware_net2280(
 
 		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
 		if (err) {
-			printk(KERN_ERR "prism54usb: firmware block upload "
+			printk(KERN_ERR "p54usb: firmware block upload "
 			       "failed\n");
 			goto fail;
 		}
@@ -682,7 +682,7 @@ static int p54u_upload_firmware_net2280(
 			  0x002C | (unsigned long)&devreg->direct_mem_win);
 		if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
 		    !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
-			printk(KERN_ERR "prism54usb: firmware DMA transfer "
+			printk(KERN_ERR "p54usb: firmware DMA transfer "
 			       "failed\n");
 			goto fail;
 		}
@@ -790,7 +790,7 @@ static int __devinit p54u_probe(struct u
 
 	dev = p54_init_common(sizeof(*priv));
 	if (!dev) {
-		printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n");
+		printk(KERN_ERR "p54usb: ieee80211 alloc failed\n");
 		return -ENOMEM;
 	}
 
@@ -846,7 +846,7 @@ static int __devinit p54u_probe(struct u
 	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
 		u8 perm_addr[ETH_ALEN];
 
-		printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
+		printk(KERN_WARNING "p54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
 		random_ether_addr(perm_addr);
 		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
 	}
@@ -855,7 +855,7 @@ static int __devinit p54u_probe(struct u
 
 	err = ieee80211_register_hw(dev);
 	if (err) {
-		printk(KERN_ERR "prism54usb: Cannot register netdevice\n");
+		printk(KERN_ERR "p54usb: Cannot register netdevice\n");
 		goto err_free_dev;
 	}
 
@@ -890,7 +890,7 @@ static void __devexit p54u_disconnect(st
 }
 
 static struct usb_driver p54u_driver = {
-	.name	= "prism54usb",
+	.name	= "p54usb",
 	.id_table = p54u_table,
 	.probe = p54u_probe,
 	.disconnect = p54u_disconnect,
drivers/net/wireless/p54/p54usb.h +3 -3
diff -Nurp a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
@@ -1,5 +1,5 @@
-#ifndef PRISM54USB_H
-#define PRISM54USB_H
+#ifndef P54USB_H
+#define P54USB_H
 
 /*
  * Defines for USB based mac80211 Prism54 driver
@@ -130,4 +130,4 @@ struct p54u_priv {
 	struct sk_buff_head rx_queue;
 };
 
-#endif /* PRISM54USB_H */
+#endif /* P54USB_H */