Commit eb189d8b authored by Michael Buesch's avatar Michael Buesch Committed by David S. Miller

b43: Add support for new firmware

This patch adds support for new firmware.
Old firmware is still supported until July 2008.

To get new firmware, go to
ftp://ftp.linksys.com/opensourcecode/wrt150nv11/1.51.3/
and download the tarball. We don't have a smaller tarball, yet.
That will be fixed later.
You can extract firmware out of the "wl_ap.o" file contained
in this tarball using latest fwcutter. You must pass the option
--unsupported to fwcutter.
Fwcutter-010 with official support for a new firmware image will
be released soon.
Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 243dcfcc
...@@ -345,3 +345,12 @@ What (Why): ...@@ -345,3 +345,12 @@ What (Why):
When: January 2009 or Linux 2.7.0, whichever comes first When: January 2009 or Linux 2.7.0, whichever comes first
Why: Superseded by newer revisions or modules Why: Superseded by newer revisions or modules
Who: Jan Engelhardt <jengelh@computergmbh.de> Who: Jan Engelhardt <jengelh@computergmbh.de>
---------------------------
What: b43 support for firmware revision < 410
When: July 2008
Why: The support code for the old firmware hurts code readability/maintainability
and slightly hurts runtime performance. Bugfixes for the old firmware
are not provided by Broadcom anymore.
Who: Michael Buesch <mb@bu3sch.de>
...@@ -807,7 +807,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ...@@ -807,7 +807,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto err_kfree_ring; goto err_kfree_ring;
if (for_tx) { if (for_tx) {
ring->txhdr_cache = kcalloc(nr_slots, ring->txhdr_cache = kcalloc(nr_slots,
sizeof(struct b43_txhdr_fw4), b43_txhdr_size(dev),
GFP_KERNEL); GFP_KERNEL);
if (!ring->txhdr_cache) if (!ring->txhdr_cache)
goto err_kfree_meta; goto err_kfree_meta;
...@@ -815,22 +815,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ...@@ -815,22 +815,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
/* test for ability to dma to txhdr_cache */ /* test for ability to dma to txhdr_cache */
dma_test = dma_map_single(dev->dev->dev, dma_test = dma_map_single(dev->dev->dev,
ring->txhdr_cache, ring->txhdr_cache,
sizeof(struct b43_txhdr_fw4), b43_txhdr_size(dev),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(dma_test)) { if (dma_mapping_error(dma_test)) {
/* ugh realloc */ /* ugh realloc */
kfree(ring->txhdr_cache); kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(nr_slots, ring->txhdr_cache = kcalloc(nr_slots,
sizeof(struct b43_txhdr_size(dev),
b43_txhdr_fw4),
GFP_KERNEL | GFP_DMA); GFP_KERNEL | GFP_DMA);
if (!ring->txhdr_cache) if (!ring->txhdr_cache)
goto err_kfree_meta; goto err_kfree_meta;
dma_test = dma_map_single(dev->dev->dev, dma_test = dma_map_single(dev->dev->dev,
ring->txhdr_cache, ring->txhdr_cache,
sizeof(struct b43_txhdr_fw4), b43_txhdr_size(dev),
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(dma_test)) if (dma_mapping_error(dma_test))
...@@ -838,7 +837,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ...@@ -838,7 +837,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
} }
dma_unmap_single(dev->dev->dev, dma_unmap_single(dev->dev->dev,
dma_test, sizeof(struct b43_txhdr_fw4), dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE); DMA_TO_DEVICE);
} }
...@@ -1122,6 +1121,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1122,6 +1121,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
struct b43_dmadesc_meta *meta_hdr; struct b43_dmadesc_meta *meta_hdr;
struct sk_buff *bounce_skb; struct sk_buff *bounce_skb;
u16 cookie; u16 cookie;
size_t hdrsize = b43_txhdr_size(ring->dev);
#define SLOTS_PER_PACKET 2 #define SLOTS_PER_PACKET 2
B43_WARN_ON(skb_shinfo(skb)->nr_frags); B43_WARN_ON(skb_shinfo(skb)->nr_frags);
...@@ -1131,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1131,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
desc = ops->idx2desc(ring, slot, &meta_hdr); desc = ops->idx2desc(ring, slot, &meta_hdr);
memset(meta_hdr, 0, sizeof(*meta_hdr)); memset(meta_hdr, 0, sizeof(*meta_hdr));
header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); header = &(ring->txhdr_cache[slot * hdrsize]);
cookie = generate_cookie(ring, slot); cookie = generate_cookie(ring, slot);
b43_generate_txhdr(ring->dev, header, b43_generate_txhdr(ring->dev, header,
skb->data, skb->len, ctl, cookie); skb->data, skb->len, ctl, cookie);
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
sizeof(struct b43_txhdr_fw4), 1); hdrsize, 1);
if (dma_mapping_error(meta_hdr->dmaaddr)) if (dma_mapping_error(meta_hdr->dmaaddr))
return -EIO; return -EIO;
ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
sizeof(struct b43_txhdr_fw4), 1, 0, 0); hdrsize, 1, 0, 0);
/* Get a slot for the payload. */ /* Get a slot for the payload. */
slot = request_slot(ring); slot = request_slot(ring);
...@@ -1189,7 +1189,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ...@@ -1189,7 +1189,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
out_unmap_hdr: out_unmap_hdr:
unmap_descbuffer(ring, meta_hdr->dmaaddr, unmap_descbuffer(ring, meta_hdr->dmaaddr,
sizeof(struct b43_txhdr_fw4), 1); hdrsize, 1);
return err; return err;
} }
...@@ -1298,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ...@@ -1298,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1); 1);
else else
unmap_descbuffer(ring, meta->dmaaddr, unmap_descbuffer(ring, meta->dmaaddr,
sizeof(struct b43_txhdr_fw4), 1); b43_txhdr_size(dev), 1);
if (meta->is_last_fragment) { if (meta->is_last_fragment) {
B43_WARN_ON(!meta->skb); B43_WARN_ON(!meta->skb);
......
...@@ -1569,11 +1569,17 @@ static void b43_release_firmware(struct b43_wldev *dev) ...@@ -1569,11 +1569,17 @@ static void b43_release_firmware(struct b43_wldev *dev)
dev->fw.initvals_band = NULL; dev->fw.initvals_band = NULL;
} }
static void b43_print_fw_helptext(struct b43_wl *wl) static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
{ {
b43err(wl, "You must go to " const char *text;
text = "You must go to "
"http://linuxwireless.org/en/users/Drivers/b43#devicefirmware " "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
"and download the correct firmware (version 4).\n"); "and download the latest firmware (version 4).\n";
if (error)
b43err(wl, text);
else
b43warn(wl, text);
} }
static int do_request_fw(struct b43_wldev *dev, static int do_request_fw(struct b43_wldev *dev,
...@@ -1725,7 +1731,7 @@ static int b43_request_firmware(struct b43_wldev *dev) ...@@ -1725,7 +1731,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
return 0; return 0;
err_load: err_load:
b43_print_fw_helptext(dev->wl); b43_print_fw_helptext(dev->wl, 1);
goto error; goto error;
err_no_ucode: err_no_ucode:
...@@ -1795,7 +1801,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) ...@@ -1795,7 +1801,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
i++; i++;
if (i >= 50) { if (i >= 50) {
b43err(dev->wl, "Microcode not responding\n"); b43err(dev->wl, "Microcode not responding\n");
b43_print_fw_helptext(dev->wl); b43_print_fw_helptext(dev->wl, 1);
err = -ENODEV; err = -ENODEV;
goto out; goto out;
} }
...@@ -1813,7 +1819,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) ...@@ -1813,7 +1819,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
"binary drivers older than version 4.x is unsupported. " "binary drivers older than version 4.x is unsupported. "
"You must upgrade your firmware files.\n"); "You must upgrade your firmware files.\n");
b43_print_fw_helptext(dev->wl); b43_print_fw_helptext(dev->wl, 1);
b43_write32(dev, B43_MMIO_MACCTL, 0); b43_write32(dev, B43_MMIO_MACCTL, 0);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out; goto out;
...@@ -1827,7 +1833,13 @@ static int b43_upload_microcode(struct b43_wldev *dev) ...@@ -1827,7 +1833,13 @@ static int b43_upload_microcode(struct b43_wldev *dev)
dev->fw.rev = fwrev; dev->fw.rev = fwrev;
dev->fw.patch = fwpatch; dev->fw.patch = fwpatch;
out: if (b43_is_old_txhdr_format(dev)) {
b43warn(dev->wl, "You are using an old firmware image. "
"Support for old firmware will be removed in July 2008.\n");
b43_print_fw_helptext(dev->wl, 0);
}
out:
return err; return err;
} }
...@@ -1887,7 +1899,7 @@ static int b43_write_initvals(struct b43_wldev *dev, ...@@ -1887,7 +1899,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
err_format: err_format:
b43err(dev->wl, "Initial Values Firmware file-format error.\n"); b43err(dev->wl, "Initial Values Firmware file-format error.\n");
b43_print_fw_helptext(dev->wl); b43_print_fw_helptext(dev->wl, 1);
return -EPROTO; return -EPROTO;
} }
...@@ -2149,13 +2161,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) ...@@ -2149,13 +2161,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
switch (antenna) { switch (antenna) {
case B43_ANTENNA0: case B43_ANTENNA0:
ant |= B43_TX4_PHY_ANT0; ant |= B43_TXH_PHY_ANT0;
break; break;
case B43_ANTENNA1: case B43_ANTENNA1:
ant |= B43_TX4_PHY_ANT1; ant |= B43_TXH_PHY_ANT1;
break;
case B43_ANTENNA2:
ant |= B43_TXH_PHY_ANT2;
break;
case B43_ANTENNA3:
ant |= B43_TXH_PHY_ANT3;
break; break;
case B43_ANTENNA_AUTO: case B43_ANTENNA_AUTO:
ant |= B43_TX4_PHY_ANTLAST; ant |= B43_TXH_PHY_ANT01AUTO;
break; break;
default: default:
B43_WARN_ON(1); B43_WARN_ON(1);
...@@ -2165,15 +2183,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) ...@@ -2165,15 +2183,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
/* For Beacons */ /* For Beacons */
tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
/* For ACK/CTS */ /* For ACK/CTS */
tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
/* For Probe Resposes */ /* For Probe Resposes */
tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL); tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
} }
...@@ -2738,6 +2756,10 @@ static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) ...@@ -2738,6 +2756,10 @@ static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
return B43_ANTENNA0; return B43_ANTENNA0;
case 2: /* Antenna 1 */ case 2: /* Antenna 1 */
return B43_ANTENNA1; return B43_ANTENNA1;
case 3: /* Antenna 2 */
return B43_ANTENNA2;
case 4: /* Antenna 3 */
return B43_ANTENNA3;
default: default:
return B43_ANTENNA_DEFAULT; return B43_ANTENNA_DEFAULT;
} }
......
...@@ -180,6 +180,8 @@ enum { ...@@ -180,6 +180,8 @@ enum {
B43_ANTENNA1, /* Antenna 0 */ B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA2,
B43_ANTENNA3 = 8,
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
......
...@@ -177,13 +177,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate) ...@@ -177,13 +177,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
return 0; return 0;
} }
static void generate_txhdr_fw4(struct b43_wldev *dev, /* Generate a TX data header. */
struct b43_txhdr_fw4 *txhdr, void b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, const struct ieee80211_tx_control *txctl,
u16 cookie) u16 cookie)
{ {
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy; const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr = const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data; (const struct ieee80211_hdr *)fragment_data;
...@@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, ...@@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
plcp_fragment_len += txctl->icv_len; plcp_fragment_len += txctl->icv_len;
key_idx = b43_kidx_to_fw(dev, key_idx); key_idx = b43_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
B43_TX4_MAC_KEYIDX; B43_TXH_MAC_KEYIDX;
mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TX4_MAC_KEYALG; B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl); wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t) txctl->iv_len, iv_len = min((size_t) txctl->iv_len,
ARRAY_SIZE(txhdr->iv)); ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
} }
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), if (b43_is_old_txhdr_format(dev)) {
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
plcp_fragment_len, rate);
} else {
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
plcp_fragment_len, rate); plcp_fragment_len, rate);
}
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
plcp_fragment_len, rate_fb); plcp_fragment_len, rate_fb);
/* Extra Frame Types */ /* Extra Frame Types */
if (rate_fb_ofdm) if (rate_fb_ofdm)
extra_ft |= B43_TX4_EFT_FBOFDM; extra_ft |= B43_TXH_EFT_FB_OFDM;
else
extra_ft |= B43_TXH_EFT_FB_CCK;
/* Set channel radio code. Note that the micrcode ORs 0x100 to /* Set channel radio code. Note that the micrcode ORs 0x100 to
* this value before comparing it to the value in SHM, if this * this value before comparing it to the value in SHM, if this
...@@ -267,19 +276,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, ...@@ -267,19 +276,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
/* PHY TX Control word */ /* PHY TX Control word */
if (rate_ofdm) if (rate_ofdm)
phy_ctl |= B43_TX4_PHY_OFDM; phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
if (dev->short_preamble) if (dev->short_preamble)
phy_ctl |= B43_TX4_PHY_SHORTPRMBL; phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
case 0: /* Default */ case 0: /* Default */
phy_ctl |= B43_TX4_PHY_ANTLAST; phy_ctl |= B43_TXH_PHY_ANT01AUTO;
break; break;
case 1: /* Antenna 0 */ case 1: /* Antenna 0 */
phy_ctl |= B43_TX4_PHY_ANT0; phy_ctl |= B43_TXH_PHY_ANT0;
break; break;
case 2: /* Antenna 1 */ case 2: /* Antenna 1 */
phy_ctl |= B43_TX4_PHY_ANT1; phy_ctl |= B43_TXH_PHY_ANT1;
break;
case 3: /* Antenna 2 */
phy_ctl |= B43_TXH_PHY_ANT2;
break;
case 4: /* Antenna 3 */
phy_ctl |= B43_TXH_PHY_ANT3;
break; break;
default: default:
B43_WARN_ON(1); B43_WARN_ON(1);
...@@ -287,16 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, ...@@ -287,16 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
/* MAC control */ /* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
mac_ctl |= B43_TX4_MAC_ACK; mac_ctl |= B43_TXH_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43_TX4_MAC_HWSEQ; mac_ctl |= B43_TXH_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
mac_ctl |= B43_TX4_MAC_STMSDU; mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A) if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TX4_MAC_5GHZ; mac_ctl |= B43_TXH_MAC_5GHZ;
if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
mac_ctl |= B43_TX4_MAC_LONGFRAME; mac_ctl |= B43_TXH_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */ /* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
...@@ -305,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, ...@@ -305,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb; int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm; int rts_rate_ofdm, rts_rate_fb_ofdm;
struct b43_plcp_hdr6 *plcp;
rts_rate = txctl->rts_cts_rate; rts_rate = txctl->rts_cts_rate;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
...@@ -312,58 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, ...@@ -312,58 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) {
cts = (struct ieee80211_cts *)
(txhdr->old_format.rts_frame);
} else {
cts = (struct ieee80211_cts *)
(txhdr->new_format.rts_frame);
}
ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
fragment_data, fragment_len, fragment_data, fragment_len,
txctl, txctl, cts);
(struct ieee80211_cts *)(txhdr-> mac_ctl |= B43_TXH_MAC_SENDCTS;
rts_frame));
mac_ctl |= B43_TX4_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts); len = sizeof(struct ieee80211_cts);
} else { } else {
struct ieee80211_rts *rts;
if (b43_is_old_txhdr_format(dev)) {
rts = (struct ieee80211_rts *)
(txhdr->old_format.rts_frame);
} else {
rts = (struct ieee80211_rts *)
(txhdr->new_format.rts_frame);
}
ieee80211_rts_get(dev->wl->hw, txctl->vif, ieee80211_rts_get(dev->wl->hw, txctl->vif,
fragment_data, fragment_len, txctl, fragment_data, fragment_len,
(struct ieee80211_rts *)(txhdr-> txctl, rts);
rts_frame)); mac_ctl |= B43_TXH_MAC_SENDRTS;
mac_ctl |= B43_TX4_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts); len = sizeof(struct ieee80211_rts);
} }
len += FCS_LEN; len += FCS_LEN;
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
rts_plcp), len, /* Generate the PLCP headers for the RTS/CTS frame */
rts_rate); if (b43_is_old_txhdr_format(dev))
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> plcp = &txhdr->old_format.rts_plcp;
rts_plcp_fb), else
plcp = &txhdr->new_format.rts_plcp;
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
len, rts_rate);
plcp = &txhdr->rts_plcp_fb;
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
len, rts_rate_fb); len, rts_rate_fb);
hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
if (b43_is_old_txhdr_format(dev)) {
hdr = (struct ieee80211_hdr *)
(&txhdr->old_format.rts_frame);
} else {
hdr = (struct ieee80211_hdr *)
(&txhdr->new_format.rts_frame);
}
txhdr->rts_dur_fb = hdr->duration_id; txhdr->rts_dur_fb = hdr->duration_id;
if (rts_rate_ofdm) { if (rts_rate_ofdm) {
extra_ft |= B43_TX4_EFT_RTSOFDM; extra_ft |= B43_TXH_EFT_RTS_OFDM;
txhdr->phy_rate_rts = txhdr->phy_rate_rts =
b43_plcp_get_ratecode_ofdm(rts_rate); b43_plcp_get_ratecode_ofdm(rts_rate);
} else } else {
extra_ft |= B43_TXH_EFT_RTS_CCK;
txhdr->phy_rate_rts = txhdr->phy_rate_rts =
b43_plcp_get_ratecode_cck(rts_rate); b43_plcp_get_ratecode_cck(rts_rate);
}
if (rts_rate_fb_ofdm) if (rts_rate_fb_ofdm)
extra_ft |= B43_TX4_EFT_RTSFBOFDM; extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
else
extra_ft |= B43_TXH_EFT_RTSFB_CCK;
} }
/* Magic cookie */ /* Magic cookie */
txhdr->cookie = cpu_to_le16(cookie); if (b43_is_old_txhdr_format(dev))
txhdr->old_format.cookie = cpu_to_le16(cookie);
else
txhdr->new_format.cookie = cpu_to_le16(cookie);
/* Apply the bitfields */ /* Apply the bitfields */
txhdr->mac_ctl = cpu_to_le32(mac_ctl); txhdr->mac_ctl = cpu_to_le32(mac_ctl);
txhdr->phy_ctl = cpu_to_le16(phy_ctl); txhdr->phy_ctl = cpu_to_le16(phy_ctl);
txhdr->extra_ft = extra_ft; txhdr->extra_ft = extra_ft;
}
void b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, u16 cookie)
{
generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
fragment_data, fragment_len, txctl, cookie);
} }
static s8 b43_rssi_postprocess(struct b43_wldev *dev, static s8 b43_rssi_postprocess(struct b43_wldev *dev,
......
...@@ -19,15 +19,15 @@ _b43_declare_plcp_hdr(6); ...@@ -19,15 +19,15 @@ _b43_declare_plcp_hdr(6);
#undef _b43_declare_plcp_hdr #undef _b43_declare_plcp_hdr
/* TX header for v4 firmware */ /* TX header for v4 firmware */
struct b43_txhdr_fw4 { struct b43_txhdr {
__le32 mac_ctl; /* MAC TX control */ __le32 mac_ctl; /* MAC TX control */
__le16 mac_frame_ctl; /* Copy of the FrameControl field */ __le16 mac_frame_ctl; /* Copy of the FrameControl field */
__le16 tx_fes_time_norm; /* TX FES Time Normal */ __le16 tx_fes_time_norm; /* TX FES Time Normal */
__le16 phy_ctl; /* PHY TX control */ __le16 phy_ctl; /* PHY TX control */
__le16 phy_ctl_0; /* Unused */ __le16 phy_ctl1; /* PHY TX control word 1 */
__le16 phy_ctl_1; /* Unused */ __le16 phy_ctl1_fb; /* PHY TX control word 1 for fallback rates */
__le16 phy_ctl_rts_0; /* Unused */ __le16 phy_ctl1_rts; /* PHY TX control word 1 RTS */
__le16 phy_ctl_rts_1; /* Unused */ __le16 phy_ctl1_rts_fb; /* PHY TX control word 1 RTS for fallback rates */
__u8 phy_rate; /* PHY rate */ __u8 phy_rate; /* PHY rate */
__u8 phy_rate_rts; /* PHY rate for RTS/CTS */ __u8 phy_rate_rts; /* PHY rate for RTS/CTS */
__u8 extra_ft; /* Extra Frame Types */ __u8 extra_ft; /* Extra Frame Types */
...@@ -35,52 +35,144 @@ struct b43_txhdr_fw4 { ...@@ -35,52 +35,144 @@ struct b43_txhdr_fw4 {
__u8 iv[16]; /* Encryption IV */ __u8 iv[16]; /* Encryption IV */
__u8 tx_receiver[6]; /* TX Frame Receiver address */ __u8 tx_receiver[6]; /* TX Frame Receiver address */
__le16 tx_fes_time_fb; /* TX FES Time Fallback */ __le16 tx_fes_time_fb; /* TX FES Time Fallback */
struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */ struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */
__le16 rts_dur_fb; /* RTS fallback duration */ __le16 rts_dur_fb; /* RTS fallback duration */
struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */ struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP header */
__le16 dur_fb; /* Fallback duration */ __le16 dur_fb; /* Fallback duration */
__le16 mm_dur_time; /* Unused */ __le16 mimo_modelen; /* MIMO mode length */
__le16 mm_dur_time_fb; /* Unused */ __le16 mimo_ratelen_fb; /* MIMO fallback rate length */
__le32 time_stamp; /* Timestamp */ __le32 timeout; /* Timeout */
union {
/* The new r410 format. */
struct {
__le16 mimo_antenna; /* MIMO antenna select */
__le16 preload_size; /* Preload size */
PAD_BYTES(2); PAD_BYTES(2);
__le16 cookie; /* TX frame cookie */ __le16 cookie; /* TX frame cookie */
__le16 tx_status; /* TX status */ __le16 tx_status; /* TX status */
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */ struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */
__u8 rts_frame[16]; /* The RTS frame (if used) */ __u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2); PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP */ struct b43_plcp_hdr6 plcp; /* Main PLCP header */
} new_format __attribute__ ((__packed__));
/* The old r351 format. */
struct {
PAD_BYTES(2);
__le16 cookie; /* TX frame cookie */
__le16 tx_status; /* TX status */
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
} old_format __attribute__ ((__packed__));
} __attribute__ ((__packed__));
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
/* MAC TX control */ /* MAC TX control */
#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ #define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
#define B43_TX4_MAC_KEYIDX_SHIFT 20 #define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */
#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ #define B43_TXH_MAC_KEYIDX_SHIFT 20
#define B43_TX4_MAC_KEYALG_SHIFT 16 #define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */
#define B43_TX4_MAC_LIFETIME 0x00001000 #define B43_TXH_MAC_KEYALG_SHIFT 16
#define B43_TX4_MAC_FRAMEBURST 0x00000800 #define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */
#define B43_TX4_MAC_SENDCTS 0x00000400 #define B43_TXH_MAC_RIFS 0x00004000 /* Use RIFS */
#define B43_TX4_MAC_AMPDU 0x00000300 #define B43_TXH_MAC_LIFETIME 0x00002000 /* Lifetime */
#define B43_TX4_MAC_AMPDU_SHIFT 8 #define B43_TXH_MAC_FRAMEBURST 0x00001000 /* Frameburst */
#define B43_TX4_MAC_5GHZ 0x00000080 #define B43_TXH_MAC_SENDCTS 0x00000800 /* Send CTS-to-self */
#define B43_TX4_MAC_IGNPMQ 0x00000020 #define B43_TXH_MAC_AMPDU 0x00000600 /* AMPDU status */
#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ #define B43_TXH_MAC_AMPDU_MPDU 0x00000000 /* Regular MPDU, not an AMPDU */
#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ #define B43_TXH_MAC_AMPDU_FIRST 0x00000200 /* First MPDU or AMPDU */
#define B43_TX4_MAC_SENDRTS 0x00000004 #define B43_TXH_MAC_AMPDU_INTER 0x00000400 /* Intermediate MPDU or AMPDU */
#define B43_TX4_MAC_LONGFRAME 0x00000002 #define B43_TXH_MAC_AMPDU_LAST 0x00000600 /* Last (or only) MPDU of AMPDU */
#define B43_TX4_MAC_ACK 0x00000001 #define B43_TXH_MAC_40MHZ 0x00000100 /* Use 40 MHz bandwidth */
#define B43_TXH_MAC_5GHZ 0x00000080 /* 5GHz band */
#define B43_TXH_MAC_DFCS 0x00000040 /* DFCS */
#define B43_TXH_MAC_IGNPMQ 0x00000020 /* Ignore PMQ */
#define B43_TXH_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
#define B43_TXH_MAC_STMSDU 0x00000008 /* Start MSDU */
#define B43_TXH_MAC_SENDRTS 0x00000004 /* Send RTS */
#define B43_TXH_MAC_LONGFRAME 0x00000002 /* Long frame */
#define B43_TXH_MAC_ACK 0x00000001 /* Immediate ACK */
/* Extra Frame Types */ /* Extra Frame Types */
#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */ #define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */
#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ #define B43_TXH_EFT_FB_CCK 0x00 /* CCK */
#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ #define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */
#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */
#define B43_TXH_EFT_FB_N 0x03 /* N */
#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */
#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */
#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */
#define B43_TXH_EFT_RTS_N 0x0C /* N */
#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */
#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */
#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */
#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */
#define B43_TXH_EFT_RTSFB_N 0x30 /* N */
/* PHY TX control word */ /* PHY TX control word */
#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ #define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */
#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ #define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */
#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */ #define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */
#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ #define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */
#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ #define B43_TXH_PHY_ENC_N 0x0003 /* N */
#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ #define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */
#define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */
#define B43_TXH_PHY_ANT1 0x0040 /* Use antenna 1 */
#define B43_TXH_PHY_ANT01AUTO 0x00C0 /* Use antenna 0/1 auto */
#define B43_TXH_PHY_ANT2 0x0100 /* Use antenna 2 */
#define B43_TXH_PHY_ANT3 0x0200 /* Use antenna 3 */
#define B43_TXH_PHY_TXPWR 0xFC00 /* TX power */
#define B43_TXH_PHY_TXPWR_SHIFT 10
/* PHY TX control word 1 */
#define B43_TXH_PHY1_BW 0x0007 /* Bandwidth */
#define B43_TXH_PHY1_BW_10 0x0000 /* 10 MHz */
#define B43_TXH_PHY1_BW_10U 0x0001 /* 10 MHz upper */
#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */
#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */
#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */
#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */
#define B43_TXH_PHY1_MODE 0x0038 /* Mode */
#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */
#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */
#define B43_TXH_PHY1_MODE_STBC 0x0010 /* STBC */
#define B43_TXH_PHY1_MODE_SDM 0x0018 /* SDM */
#define B43_TXH_PHY1_CRATE 0x0700 /* Coding rate */
#define B43_TXH_PHY1_CRATE_1_2 0x0000 /* 1/2 */
#define B43_TXH_PHY1_CRATE_2_3 0x0100 /* 2/3 */
#define B43_TXH_PHY1_CRATE_3_4 0x0200 /* 3/4 */
#define B43_TXH_PHY1_CRATE_4_5 0x0300 /* 4/5 */
#define B43_TXH_PHY1_CRATE_5_6 0x0400 /* 5/6 */
#define B43_TXH_PHY1_CRATE_7_8 0x0600 /* 7/8 */
#define B43_TXH_PHY1_MODUL 0x3800 /* Modulation scheme */
#define B43_TXH_PHY1_MODUL_BPSK 0x0000 /* BPSK */
#define B43_TXH_PHY1_MODUL_QPSK 0x0800 /* QPSK */
#define B43_TXH_PHY1_MODUL_QAM16 0x1000 /* QAM16 */
#define B43_TXH_PHY1_MODUL_QAM64 0x1800 /* QAM64 */
#define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */
/* r351 firmware compatibility stuff. */
static inline
bool b43_is_old_txhdr_format(struct b43_wldev *dev)
{
return (dev->fw.rev <= 351);
}
static inline
size_t b43_txhdr_size(struct b43_wldev *dev)
{
if (b43_is_old_txhdr_format(dev))
return 100 + sizeof(struct b43_plcp_hdr6);
return 104 + sizeof(struct b43_plcp_hdr6);
}
void b43_generate_txhdr(struct b43_wldev *dev, void b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr, u8 * txhdr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment