2007-08-05 23:18:29

by Daniel Drake

[permalink] [raw]
Subject: [PATCH] zd1211rw-mac80211: consistent handling of ZD1211 specific rates

From: Ulrich Kunitz <[email protected]>

As pointed out by Daniel Drake, the zd1211rw driver used several
different rate values and names throughout the driver. He has
written a patch to change it and tweaked it after some pretty wild
ideas from my side. But the discussion helped me to understand the
problem better and I think I have nailed it down with this patch.

A zd-rate will consist from now on of a four-bit "pure" rate value
and a modulation type flag as used in the ZD1211 control set used
for packet transmission. This is consistent with the usage in the
zd_rates table. If possible these zd-rates should be used in the
code.

Signed-off-by: Ulrich Kunitz <[email protected]>
Signed-off-by: Daniel Drake <[email protected]>
---
drivers/net/wireless/zd1211rw-mac80211/zd_chip.c | 54 ++++++++-------
drivers/net/wireless/zd1211rw-mac80211/zd_chip.h | 5 +-
.../net/wireless/zd1211rw-mac80211/zd_ieee80211.h | 42 +++++++----
drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 72 ++++++++++---------
drivers/net/wireless/zd1211rw-mac80211/zd_mac.h | 62 ++++++++++++-----
5 files changed, 139 insertions(+), 96 deletions(-)

diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
index 5adefd8..4513675 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
@@ -1308,7 +1308,7 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
return r;
}

-static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
{
static const u16 constants[] = {
715, 655, 585, 540, 470, 410, 360, 315,
@@ -1322,7 +1322,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
/* It seems that their quality parameter is somehow per signal
* and is now transferred per bit.
*/
- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_12M:
case ZD_OFDM_RATE_24M:
@@ -1349,7 +1349,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
break;
}

- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_9M:
i += 3;
@@ -1373,11 +1373,11 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
return i;
}

-static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
{
int r;

- r = ofdm_qual_db(status_quality, rate, size);
+ r = ofdm_qual_db(status_quality, zd_rate, size);
ZD_ASSERT(r >= 0);
if (r < 0)
r = 0;
@@ -1438,52 +1438,54 @@ static int cck_qual_percent(u8 status_quality)
return r <= 100 ? r : 100;
}

+static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
+{
+ return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
+}
+
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status)
{
return (status->frame_status&ZD_RX_OFDM) ?
ofdm_qual_percent(status->signal_quality_ofdm,
- zd_ofdm_plcp_header_rate(rx_frame),
+ zd_rate_from_ofdm_plcp_header(rx_frame),
size) :
cck_qual_percent(status->signal_quality_cck);
}

/**
- * zd_rx_rate - report rate as expected by mac80211
+ * zd_rx_rate - report zd-rate
* @rx_frame - received frame
* @rx_status - rx_status as given by the device
*
- * This function converts the rate as provided in struct rx_status to the
- * format expected by the mac80211 stack. The stack expects the reported rate
- * to use the same format as used in the rates table. This driver has to use
- * the same values as used in the tx control set.
+ * This function converts the rate as encoded in the received packet to the
+ * zd-rate, we are using on other places in the driver.
*/
-u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
{
- u16 rate;
+ u8 zd_rate;
if (status->frame_status & ZD_RX_OFDM) {
- rate = ZD_CS_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
+ zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame);
} else {
- u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
- switch (cck_rate) {
- case ZD_CCK_SIGNAL_1M:
- rate = ZD_CS_CCK | ZD_CS_CCK_RATE_1M;
+ switch (zd_cck_plcp_header_signal(rx_frame)) {
+ case ZD_CCK_PLCP_SIGNAL_1M:
+ zd_rate = ZD_CCK_RATE_1M;
break;
- case ZD_CCK_SIGNAL_2M:
- rate = ZD_CS_CCK | ZD_CS_CCK_RATE_2M;
+ case ZD_CCK_PLCP_SIGNAL_2M:
+ zd_rate = ZD_CCK_RATE_2M;
break;
- case ZD_CCK_SIGNAL_5M5:
- rate = ZD_CS_CCK | ZD_CS_CCK_RATE_5_5M;
+ case ZD_CCK_PLCP_SIGNAL_5M5:
+ zd_rate = ZD_CCK_RATE_5_5M;
break;
- case ZD_CCK_SIGNAL_11M:
- rate = ZD_CS_CCK | ZD_CS_CCK_RATE_11M;
+ case ZD_CCK_PLCP_SIGNAL_11M:
+ zd_rate = ZD_CCK_RATE_11M;
break;
default:
- rate = 0;
+ zd_rate = 0;
}
}

- return rate;
+ return zd_rate;
}

int zd_chip_switch_radio_on(struct zd_chip *chip)
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
index 1ab15a0..1145827 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
@@ -433,9 +433,10 @@ enum {
#define CR_GROUP_HASH_P2 CTL_REG(0x0628)

#define CR_RX_TIMEOUT CTL_REG(0x062C)
+
/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
* device will use a rate in this table that is less than or equal to the rate
- * of the incoming frame which prompted the response */
+ * of the incoming frame which prompted the response. */
#define CR_BASIC_RATE_TBL CTL_REG(0x0630)
#define CR_RATE_1M (1 << 0) /* 802.11b */
#define CR_RATE_2M (1 << 1) /* 802.11b */
@@ -873,7 +874,7 @@ struct rx_status;
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status);

-u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);

struct zd_mc_hash {
u32 low;
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_ieee80211.h b/drivers/net/wireless/zd1211rw-mac80211/zd_ieee80211.h
index 6485f98..98b87cf 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_ieee80211.h
@@ -28,20 +28,25 @@ struct ofdm_plcp_header {
__le16 service;
} __attribute__((packed));

-static inline u8 zd_ofdm_plcp_header_rate(
- const struct ofdm_plcp_header *header)
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
{
return header->prefix[0] & 0xf;
}

-#define ZD_OFDM_RATE_6M 0xb
-#define ZD_OFDM_RATE_9M 0xf
-#define ZD_OFDM_RATE_12M 0xa
-#define ZD_OFDM_RATE_18M 0xe
-#define ZD_OFDM_RATE_24M 0x9
-#define ZD_OFDM_RATE_36M 0xd
-#define ZD_OFDM_RATE_48M 0x8
-#define ZD_OFDM_RATE_54M 0xc
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M 0xb
+#define ZD_OFDM_PLCP_RATE_9M 0xf
+#define ZD_OFDM_PLCP_RATE_12M 0xa
+#define ZD_OFDM_PLCP_RATE_18M 0xe
+#define ZD_OFDM_PLCP_RATE_24M 0x9
+#define ZD_OFDM_PLCP_RATE_36M 0xd
+#define ZD_OFDM_PLCP_RATE_48M 0x8
+#define ZD_OFDM_PLCP_RATE_54M 0xc

struct cck_plcp_header {
u8 signal;
@@ -50,14 +55,21 @@ struct cck_plcp_header {
__le16 crc16;
} __attribute__((packed));

-static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
{
return header->signal;
}

-#define ZD_CCK_SIGNAL_1M 0x0a
-#define ZD_CCK_SIGNAL_2M 0x14
-#define ZD_CCK_SIGNAL_5M5 0x37
-#define ZD_CCK_SIGNAL_11M 0x6e
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M 0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M 0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
+#define ZD_CCK_PLCP_SIGNAL_11M 0x6e

#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
index d646bfd..cef5492 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
@@ -28,46 +28,46 @@
#include "zd_rf.h"
#include "zd_util.h"

-/* TODO: remove this once we have a general modes/channels/rates filling func */
+/* This table contains the hardware specific values for the modulation rates. */
static const struct ieee80211_rate zd_rates[] = {
{ .rate = 10,
- .val = ZD_CS_CCK | ZD_CS_CCK_RATE_1M,
+ .val = ZD_CCK_RATE_1M,
.flags = IEEE80211_RATE_CCK },
{ .rate = 20,
- .val = ZD_CS_CCK | ZD_CS_CCK_RATE_2M,
- .val2 = ZD_CS_CCK | ZD_CS_CCK_RATE_2M | ZD_CS_CCK_PREA_SHORT,
+ .val = ZD_CCK_RATE_2M,
+ .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT,
.flags = IEEE80211_RATE_CCK_2 },
{ .rate = 55,
- .val = ZD_CS_CCK | ZD_CS_CCK_RATE_5_5M,
- .val2 = ZD_CS_CCK | ZD_CS_CCK_RATE_5_5M | ZD_CS_CCK_PREA_SHORT,
+ .val = ZD_CCK_RATE_5_5M,
+ .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT,
.flags = IEEE80211_RATE_CCK_2 },
{ .rate = 110,
- .val = ZD_CS_CCK | ZD_CS_CCK_RATE_11M,
- .val2 = ZD_CS_CCK | ZD_CS_CCK_RATE_11M | ZD_CS_CCK_PREA_SHORT,
+ .val = ZD_CCK_RATE_11M,
+ .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT,
.flags = IEEE80211_RATE_CCK_2 },
{ .rate = 60,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_6M,
+ .val = ZD_OFDM_RATE_6M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 90,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_9M,
+ .val = ZD_OFDM_RATE_9M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 120,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_12M,
+ .val = ZD_OFDM_RATE_12M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 180,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_18M,
+ .val = ZD_OFDM_RATE_18M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 240,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_24M,
+ .val = ZD_OFDM_RATE_24M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 360,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_36M,
+ .val = ZD_OFDM_RATE_36M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 480,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_48M,
+ .val = ZD_OFDM_RATE_48M,
.flags = IEEE80211_RATE_OFDM },
{ .rate = 540,
- .val = ZD_CS_OFDM | ZD_OFDM_RATE_54M,
+ .val = ZD_OFDM_RATE_54M,
.flags = IEEE80211_RATE_OFDM },
};

@@ -426,35 +426,39 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
}
}

-static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length)
+static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
{
+ /* ZD_PURE_RATE() must be used to remove the modulation type flag of
+ * the zd-rate values.
+ */
static const u8 rate_divisor[] = {
- [ZD_CS_CCK_RATE_1M] = 1,
- [ZD_CS_CCK_RATE_2M] = 2,
- [ZD_CS_CCK_RATE_5_5M] = 11, /* bits must be doubled */
- [ZD_CS_CCK_RATE_11M] = 11,
- [ZD_OFDM_RATE_6M] = 6,
- [ZD_OFDM_RATE_9M] = 9,
- [ZD_OFDM_RATE_12M] = 12,
- [ZD_OFDM_RATE_18M] = 18,
- [ZD_OFDM_RATE_24M] = 24,
- [ZD_OFDM_RATE_36M] = 36,
- [ZD_OFDM_RATE_48M] = 48,
- [ZD_OFDM_RATE_54M] = 54,
+ [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1,
+ [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2,
+ /* Bits must be doubled. */
+ [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11,
+ [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54,
};

u32 bits = (u32)tx_length * 8;
u32 divisor;

- divisor = rate_divisor[cs_rate];
+ divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
if (divisor == 0)
return -EINVAL;

- switch (cs_rate) {
- case ZD_CS_CCK_RATE_5_5M:
+ switch (zd_rate) {
+ case ZD_CCK_RATE_5_5M:
bits = (2*bits) + 10; /* round up to the next integer */
break;
- case ZD_CS_CCK_RATE_11M:
+ case ZD_CCK_RATE_11M:
if (service) {
u32 t = bits % 11;
*service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;
@@ -555,7 +559,7 @@ static int fill_ctrlset(struct zd_mac *mac,
* - see line 53 of zdinlinef.h
*/
cs->service = 0;
- r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation),
le16_to_cpu(cs->tx_length));
if (r < 0)
return r;
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
index 4255b10..27289a7 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
@@ -37,27 +37,51 @@ struct zd_ctrlset {

#define ZD_CS_RESERVED_SIZE 25

-/* zd_crtlset field modulation */
-#define ZD_CS_RATE_MASK 0x0f
-#define ZD_CS_TYPE_MASK 0x10
-#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
-#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
-
-#define ZD_CS_CCK 0x00
-#define ZD_CS_OFDM 0x10
-
-#define ZD_CS_CCK_RATE_1M 0x00
-#define ZD_CS_CCK_RATE_2M 0x01
-#define ZD_CS_CCK_RATE_5_5M 0x02
-#define ZD_CS_CCK_RATE_11M 0x03
-/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+/* The field modulation of struct zd_ctrlset controls the bit rate, the use
+ * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or
+ * 802.11g in OFDM mode.
+ *
+ * The term zd-rate is used for the combination of the modulation type flag
+ * and the "pure" rate value.
+ */
+#define ZD_PURE_RATE_MASK 0x0f
+#define ZD_MODULATION_TYPE_MASK 0x10
+#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK)
+#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK)
+#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK)
+#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK)
+
+/* The two possible modulation types. Notify that 802.11b doesn't use the CCK
+ * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain
+ * consistent with uses the term at other places.
*/
+#define ZD_CCK 0x00
+#define ZD_OFDM 0x10

-/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
-#define ZD_CS_CCK_PREA_LONG 0x00
-#define ZD_CS_CCK_PREA_SHORT 0x20
-#define ZD_CS_OFDM_MODE_11G 0x00
-#define ZD_CS_OFDM_MODE_11A 0x20
+/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates.
+ * For OFDM the PLCP rate encodings are used. We combine these "pure" rates
+ * with the modulation type flag and call the resulting values zd-rates.
+ */
+#define ZD_CCK_RATE_1M (ZD_CCK|0x00)
+#define ZD_CCK_RATE_2M (ZD_CCK|0x01)
+#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02)
+#define ZD_CCK_RATE_11M (ZD_CCK|0x03)
+#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M)
+#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M)
+#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M)
+#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M)
+#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M)
+#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M)
+#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M)
+#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M)
+
+/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK
+ * mode or the 802.11a/802.11g selection in OFDM mode.
+ */
+#define ZD_CCK_PREA_LONG 0x00
+#define ZD_CCK_PREA_SHORT 0x20
+#define ZD_OFDM_MODE_11G 0x00
+#define ZD_OFDM_MODE_11A 0x20

/* zd_ctrlset control field */
#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
--
1.5.2.4