[PATCH] zd1211rw: consistent handling of ZD1211 specific rates
authorUlrich Kunitz <kune@deine-taler.de>
Mon, 6 Aug 2007 00:24:31 +0000 (01:24 +0100)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 10 Oct 2007 23:50:32 +0000 (16:50 -0700)
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 <kune@deine-taler.de>
Signed-off-by: Daniel Drake <dsd@gentoo.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_ieee80211.h
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_mac.h

index 7e3c0625129b9b206e3f549dd2a0c8e9bacbb443..495904218b1b205169d78aa458d742ddcca36030 100644 (file)
@@ -1009,19 +1009,19 @@ int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
        u32 value = 0;
 
        /* Modulation bit */
-       if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM)
+       if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
                rts_mod = ZD_RX_OFDM;
 
        dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
                rts_rate, preamble);
 
-       value |= rts_rate << RTSCTS_SH_RTS_RATE;
+       value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
        value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
        value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
        value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
 
        /* We always send 11M self-CTS messages, like the vendor driver. */
-       value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE;
+       value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
        value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
 
        return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE);
@@ -1328,7 +1328,7 @@ int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates)
        return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
 }
 
-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,
@@ -1342,7 +1342,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:
@@ -1369,7 +1369,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;
@@ -1393,11 +1393,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;
@@ -1458,12 +1458,17 @@ 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);
 }
@@ -1479,32 +1484,32 @@ u8 zd_rx_strength_percent(u8 rssi)
 u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
 {
        static const u16 ofdm_rates[] = {
-               [ZD_OFDM_RATE_6M]  = 60,
-               [ZD_OFDM_RATE_9M]  = 90,
-               [ZD_OFDM_RATE_12M] = 120,
-               [ZD_OFDM_RATE_18M] = 180,
-               [ZD_OFDM_RATE_24M] = 240,
-               [ZD_OFDM_RATE_36M] = 360,
-               [ZD_OFDM_RATE_48M] = 480,
-               [ZD_OFDM_RATE_54M] = 540,
+               [ZD_OFDM_PLCP_RATE_6M]  = 60,
+               [ZD_OFDM_PLCP_RATE_9M]  = 90,
+               [ZD_OFDM_PLCP_RATE_12M] = 120,
+               [ZD_OFDM_PLCP_RATE_18M] = 180,
+               [ZD_OFDM_PLCP_RATE_24M] = 240,
+               [ZD_OFDM_PLCP_RATE_36M] = 360,
+               [ZD_OFDM_PLCP_RATE_48M] = 480,
+               [ZD_OFDM_PLCP_RATE_54M] = 540,
        };
        u16 rate;
        if (status->frame_status & ZD_RX_OFDM) {
+               /* Deals with PLCP OFDM rate (not zd_rates) */
                u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
                rate = ofdm_rates[ofdm_rate & 0xf];
        } else {
-               u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
-               switch (cck_rate) {
-               case ZD_CCK_SIGNAL_1M:
+               switch (zd_cck_plcp_header_signal(rx_frame)) {
+               case ZD_CCK_PLCP_SIGNAL_1M:
                        rate = 10;
                        break;
-               case ZD_CCK_SIGNAL_2M:
+               case ZD_CCK_PLCP_SIGNAL_2M:
                        rate = 20;
                        break;
-               case ZD_CCK_SIGNAL_5M5:
+               case ZD_CCK_PLCP_SIGNAL_5M5:
                        rate = 55;
                        break;
-               case ZD_CCK_SIGNAL_11M:
+               case ZD_CCK_PLCP_SIGNAL_11M:
                        rate = 110;
                        break;
                default:
index c4f36d39642b1bdeccf8106415da7a337448acf9..fbf6491dce7e00d45a0ecdaca36ca76a3f0b0a0e 100644 (file)
@@ -43,21 +43,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;
 }
 
-/* These are referred to as zd_rates */
-#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;
@@ -66,15 +70,22 @@ 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
 
 enum ieee80211_std {
        IEEE80211B = 0x01,
index 7ec1fcf37fc38ddeaa29c0fc2168559dd8be51ff..451308d7095d2b2a84d105b8bd736817221ed6e6 100644 (file)
@@ -610,28 +610,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac)
        return channel;
 }
 
-/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
-static u8 zd_rate_typed(u8 zd_rate)
-{
-       static const u8 typed_rates[16] = {
-               [ZD_CCK_RATE_1M]        = ZD_CS_CCK|ZD_CCK_RATE_1M,
-               [ZD_CCK_RATE_2M]        = ZD_CS_CCK|ZD_CCK_RATE_2M,
-               [ZD_CCK_RATE_5_5M]      = ZD_CS_CCK|ZD_CCK_RATE_5_5M,
-               [ZD_CCK_RATE_11M]       = ZD_CS_CCK|ZD_CCK_RATE_11M,
-               [ZD_OFDM_RATE_6M]       = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
-               [ZD_OFDM_RATE_9M]       = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
-               [ZD_OFDM_RATE_12M]      = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
-               [ZD_OFDM_RATE_18M]      = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
-               [ZD_OFDM_RATE_24M]      = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
-               [ZD_OFDM_RATE_36M]      = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
-               [ZD_OFDM_RATE_48M]      = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
-               [ZD_OFDM_RATE_54M]      = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
-       };
-
-       ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
-       return typed_rates[zd_rate & ZD_CS_RATE_MASK];
-}
-
 int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
 {
        struct ieee80211_device *ieee;
@@ -739,25 +717,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
 
 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_CCK_RATE_1M]        =  1,
-               [ZD_CCK_RATE_2M]        =  2,
-               [ZD_CCK_RATE_5_5M]      = 11, /* bits must be doubled */
-               [ZD_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[zd_rate];
+       divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
        if (divisor == 0)
                return -EINVAL;
 
@@ -780,52 +763,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
        return bits/divisor;
 }
 
-enum {
-       R2M_SHORT_PREAMBLE = 0x01,
-       R2M_11A            = 0x02,
-};
-
-static u8 zd_rate_to_modulation(u8 zd_rate, int flags)
-{
-       u8 modulation;
-
-       modulation = zd_rate_typed(zd_rate);
-       if (flags & R2M_SHORT_PREAMBLE) {
-               switch (ZD_CS_RATE(modulation)) {
-               case ZD_CCK_RATE_2M:
-               case ZD_CCK_RATE_5_5M:
-               case ZD_CCK_RATE_11M:
-                       modulation |= ZD_CS_CCK_PREA_SHORT;
-                       return modulation;
-               }
-       }
-       if (flags & R2M_11A) {
-               if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
-                       modulation |= ZD_CS_OFDM_MODE_11A;
-       }
-       return modulation;
-}
-
 static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
                              struct ieee80211_hdr_4addr *hdr)
 {
        struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
        u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
-       u8 rate, zd_rate;
+       u8 rate;
        int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
        int is_multicast = is_multicast_ether_addr(hdr->addr1);
        int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
                is_multicast, is_mgt);
-       int flags = 0;
 
-       /* FIXME: 802.11a? */
        rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
+       cs->modulation = rate_to_zd_rate(rate);
 
-       if (short_preamble)
-               flags |= R2M_SHORT_PREAMBLE;
-
-       zd_rate = rate_to_zd_rate(rate);
-       cs->modulation = zd_rate_to_modulation(zd_rate, flags);
+       /* Set short preamble bit when appropriate */
+       if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
+           && cs->modulation != ZD_CCK_RATE_1M)
+               cs->modulation |= ZD_CCK_PREA_SHORT;
 }
 
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
@@ -864,7 +819,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
                cs->control |= ZD_CS_RTS;
 
        /* Use CTS-to-self protection if required */
-       if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM &&
+       if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
                        ieee80211softmac_protection_needed(softmac)) {
                /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
                cs->control &= ~ZD_CS_RTS;
@@ -925,7 +880,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;
@@ -934,7 +889,7 @@ static int fill_ctrlset(struct zd_mac *mac,
        if (next_frag_len == 0) {
                cs->next_frame_length = 0;
        } else {
-               r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+               r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
                                         next_frag_len);
                if (r < 0)
                        return r;
index 9f9344eb50f943a922b3a7a09eddb1bb4fe22db4..1b15bde3ff60a35599a86361778605e926b71963 100644 (file)
@@ -40,28 +40,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
-
-/* These are referred to as zd_rates */
-#define ZD_CCK_RATE_1M 0x00
-#define ZD_CCK_RATE_2M 0x01
-#define ZD_CCK_RATE_5_5M       0x02
-#define ZD_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.
  */
-
-/* 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
+#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
+
+/* 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