Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -345,3 +345,12 @@ What (Why):
When:	January 2009 or Linux 2.7.0, whichever comes first
Why:	Superseded by newer revisions or modules
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>
+11 −11
Original line number Diff line number Diff line
@@ -807,7 +807,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
		goto err_kfree_ring;
	if (for_tx) {
		ring->txhdr_cache = kcalloc(nr_slots,
					    sizeof(struct b43_txhdr_fw4),
					    b43_txhdr_size(dev),
					    GFP_KERNEL);
		if (!ring->txhdr_cache)
			goto err_kfree_meta;
@@ -815,22 +815,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
		/* test for ability to dma to txhdr_cache */
		dma_test = dma_map_single(dev->dev->dev,
					  ring->txhdr_cache,
					  sizeof(struct b43_txhdr_fw4),
					  b43_txhdr_size(dev),
					  DMA_TO_DEVICE);

		if (dma_mapping_error(dma_test)) {
			/* ugh realloc */
			kfree(ring->txhdr_cache);
			ring->txhdr_cache = kcalloc(nr_slots,
						    sizeof(struct
							   b43_txhdr_fw4),
						    b43_txhdr_size(dev),
						    GFP_KERNEL | GFP_DMA);
			if (!ring->txhdr_cache)
				goto err_kfree_meta;

			dma_test = dma_map_single(dev->dev->dev,
						  ring->txhdr_cache,
						  sizeof(struct b43_txhdr_fw4),
						  b43_txhdr_size(dev),
						  DMA_TO_DEVICE);

			if (dma_mapping_error(dma_test))
@@ -838,7 +837,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
		}

		dma_unmap_single(dev->dev->dev,
				 dma_test, sizeof(struct b43_txhdr_fw4),
				 dma_test, b43_txhdr_size(dev),
				 DMA_TO_DEVICE);
	}

@@ -1122,6 +1121,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
	struct b43_dmadesc_meta *meta_hdr;
	struct sk_buff *bounce_skb;
	u16 cookie;
	size_t hdrsize = b43_txhdr_size(ring->dev);

#define SLOTS_PER_PACKET  2
	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
@@ -1131,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
	desc = ops->idx2desc(ring, slot, &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);
	b43_generate_txhdr(ring->dev, header,
			   skb->data, skb->len, ctl, cookie);

	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
					   sizeof(struct b43_txhdr_fw4), 1);
					   hdrsize, 1);
	if (dma_mapping_error(meta_hdr->dmaaddr))
		return -EIO;
	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. */
	slot = request_slot(ring);
@@ -1189,7 +1189,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
	dev_kfree_skb_any(skb);
out_unmap_hdr:
	unmap_descbuffer(ring, meta_hdr->dmaaddr,
			 sizeof(struct b43_txhdr_fw4), 1);
			 hdrsize, 1);
	return err;
}

@@ -1298,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
					 1);
		else
			unmap_descbuffer(ring, meta->dmaaddr,
					 sizeof(struct b43_txhdr_fw4), 1);
					 b43_txhdr_size(dev), 1);

		if (meta->is_last_fragment) {
			B43_WARN_ON(!meta->skb);
+36 −14
Original line number Diff line number Diff line
@@ -1569,11 +1569,17 @@ static void b43_release_firmware(struct b43_wldev *dev)
	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 "
	       "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,
@@ -1725,7 +1731,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
	return 0;

err_load:
	b43_print_fw_helptext(dev->wl);
	b43_print_fw_helptext(dev->wl, 1);
	goto error;

err_no_ucode:
@@ -1795,7 +1801,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
		i++;
		if (i >= 50) {
			b43err(dev->wl, "Microcode not responding\n");
			b43_print_fw_helptext(dev->wl);
			b43_print_fw_helptext(dev->wl, 1);
			err = -ENODEV;
			goto out;
		}
@@ -1813,7 +1819,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
		b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
		       "binary drivers older than version 4.x is unsupported. "
		       "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);
		err = -EOPNOTSUPP;
		goto out;
@@ -1827,6 +1833,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
	dev->fw.rev = fwrev;
	dev->fw.patch = fwpatch;

	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;
}
@@ -1887,7 +1899,7 @@ static int b43_write_initvals(struct b43_wldev *dev,

err_format:
	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;
}
@@ -2149,13 +2161,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)

	switch (antenna) {
	case B43_ANTENNA0:
		ant |= B43_TX4_PHY_ANT0;
		ant |= B43_TXH_PHY_ANT0;
		break;
	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;
	case B43_ANTENNA_AUTO:
		ant |= B43_TX4_PHY_ANTLAST;
		ant |= B43_TXH_PHY_ANT01AUTO;
		break;
	default:
		B43_WARN_ON(1);
@@ -2165,15 +2183,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)

	/* For Beacons */
	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);
	/* For ACK/CTS */
	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);
	/* For Probe Resposes */
	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);
}

@@ -2738,6 +2756,10 @@ static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
		return B43_ANTENNA0;
	case 2:		/* Antenna 1 */
		return B43_ANTENNA1;
	case 3:		/* Antenna 2 */
		return B43_ANTENNA2;
	case 4:		/* Antenna 3 */
		return B43_ANTENNA3;
	default:
		return B43_ANTENNA_DEFAULT;
	}
+2 −0
Original line number Diff line number Diff line
@@ -180,6 +180,8 @@ enum {
	B43_ANTENNA1,		/* Antenna 0 */
	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
	B43_ANTENNA2,
	B43_ANTENNA3 = 8,

	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
+94 −50
Original line number Diff line number Diff line
@@ -177,13 +177,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
	return 0;
}

static void generate_txhdr_fw4(struct b43_wldev *dev,
			       struct b43_txhdr_fw4 *txhdr,
/* Generate a TX data header. */
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)
{
	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
	const struct b43_phy *phy = &dev->phy;
	const struct ieee80211_hdr *wlhdr =
	    (const struct ieee80211_hdr *)fragment_data;
@@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
		plcp_fragment_len += txctl->icv_len;

		key_idx = b43_kidx_to_fw(dev, key_idx);
		mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
			   B43_TX4_MAC_KEYIDX;
		mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
			   B43_TX4_MAC_KEYALG;
		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
			   B43_TXH_MAC_KEYIDX;
		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
			   B43_TXH_MAC_KEYALG;
		wlhdr_len = ieee80211_get_hdrlen(fctl);
		iv_len = min((size_t) txctl->iv_len,
			     ARRAY_SIZE(txhdr->iv));
		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);
	}
	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
			      plcp_fragment_len, rate_fb);

	/* Extra Frame Types */
	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
	 * 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,

	/* PHY TX Control word */
	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)
		phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
		phy_ctl |= B43_TXH_PHY_SHORTPRMBL;

	switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
	case 0: /* Default */
		phy_ctl |= B43_TX4_PHY_ANTLAST;
		phy_ctl |= B43_TXH_PHY_ANT01AUTO;
		break;
	case 1: /* Antenna 0 */
		phy_ctl |= B43_TX4_PHY_ANT0;
		phy_ctl |= B43_TXH_PHY_ANT0;
		break;
	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;
	default:
		B43_WARN_ON(1);
@@ -287,16 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,

	/* MAC control */
	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) &&
	      ((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)
		mac_ctl |= B43_TX4_MAC_STMSDU;
		mac_ctl |= B43_TXH_MAC_STMSDU;
	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)
		mac_ctl |= B43_TX4_MAC_LONGFRAME;
		mac_ctl |= B43_TXH_MAC_LONGFRAME;

	/* Generate the RTS or CTS-to-self frame */
	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
@@ -305,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
		struct ieee80211_hdr *hdr;
		int rts_rate, rts_rate_fb;
		int rts_rate_ofdm, rts_rate_fb_ofdm;
		struct b43_plcp_hdr6 *plcp;

		rts_rate = txctl->rts_cts_rate;
		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
@@ -312,58 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);

		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,
						fragment_data, fragment_len,
						txctl,
						(struct ieee80211_cts *)(txhdr->
									 rts_frame));
			mac_ctl |= B43_TX4_MAC_SENDCTS;
						txctl, cts);
			mac_ctl |= B43_TXH_MAC_SENDCTS;
			len = sizeof(struct ieee80211_cts);
		} 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,
					  fragment_data, fragment_len, txctl,
					  (struct ieee80211_rts *)(txhdr->
								   rts_frame));
			mac_ctl |= B43_TX4_MAC_SENDRTS;
					  fragment_data, fragment_len,
					  txctl, rts);
			mac_ctl |= B43_TXH_MAC_SENDRTS;
			len = sizeof(struct ieee80211_rts);
		}
		len += FCS_LEN;
		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
							       rts_plcp), len,
				      rts_rate);
		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
							       rts_plcp_fb),

		/* Generate the PLCP headers for the RTS/CTS frame */
		if (b43_is_old_txhdr_format(dev))
			plcp = &txhdr->old_format.rts_plcp;
		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);
		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;

		if (rts_rate_ofdm) {
			extra_ft |= B43_TX4_EFT_RTSOFDM;
			extra_ft |= B43_TXH_EFT_RTS_OFDM;
			txhdr->phy_rate_rts =
			    b43_plcp_get_ratecode_ofdm(rts_rate);
		} else
		} else {
			extra_ft |= B43_TXH_EFT_RTS_CCK;
			txhdr->phy_rate_rts =
			    b43_plcp_get_ratecode_cck(rts_rate);
		}
		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 */
	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 */
	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
	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,
Loading