diff options
Diffstat (limited to 'drivers/net/wireless/b43/xmit.c')
| -rw-r--r-- | drivers/net/wireless/b43/xmit.c | 278 | 
1 files changed, 213 insertions, 65 deletions
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index e6b0528f3b5..6e6ef3fc224 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -6,7 +6,7 @@    Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>    Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> -  Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> +  Copyright (C) 2005, 2006 Michael Buesch <m@bues.ch>    Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>    Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -32,6 +32,36 @@  #include "dma.h"  #include "pio.h" +static const struct b43_tx_legacy_rate_phy_ctl_entry b43_tx_legacy_rate_phy_ctl[] = { +	{ B43_CCK_RATE_1MB,	0x0,			0x0 }, +	{ B43_CCK_RATE_2MB,	0x0,			0x1 }, +	{ B43_CCK_RATE_5MB,	0x0,			0x2 }, +	{ B43_CCK_RATE_11MB,	0x0,			0x3 }, +	{ B43_OFDM_RATE_6MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_BPSK }, +	{ B43_OFDM_RATE_9MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_BPSK }, +	{ B43_OFDM_RATE_12MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_QPSK }, +	{ B43_OFDM_RATE_18MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QPSK }, +	{ B43_OFDM_RATE_24MB,	B43_TXH_PHY1_CRATE_1_2,	B43_TXH_PHY1_MODUL_QAM16 }, +	{ B43_OFDM_RATE_36MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QAM16 }, +	{ B43_OFDM_RATE_48MB,	B43_TXH_PHY1_CRATE_2_3,	B43_TXH_PHY1_MODUL_QAM64 }, +	{ B43_OFDM_RATE_54MB,	B43_TXH_PHY1_CRATE_3_4,	B43_TXH_PHY1_MODUL_QAM64 }, +}; + +static const struct b43_tx_legacy_rate_phy_ctl_entry * +b43_tx_legacy_rate_phy_ctl_ent(u8 bitrate) +{ +	const struct b43_tx_legacy_rate_phy_ctl_entry *e; +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(b43_tx_legacy_rate_phy_ctl); i++) { +		e = &(b43_tx_legacy_rate_phy_ctl[i]); +		if (e->bitrate == bitrate) +			return e; +	} + +	B43_WARN_ON(1); +	return NULL; +}  /* Extract the bitrate index out of a CCK PLCP header. */  static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) @@ -145,6 +175,35 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,  	}  } +/* TODO: verify if needed for SSLPN or LCN  */ +static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) +{ +	const struct b43_phy *phy = &dev->phy; +	const struct b43_tx_legacy_rate_phy_ctl_entry *e; +	u16 control = 0; +	u16 bw; + +	if (phy->type == B43_PHYTYPE_LP) +		bw = B43_TXH_PHY1_BW_20; +	else /* FIXME */ +		bw = B43_TXH_PHY1_BW_20; + +	if (0) { /* FIXME: MIMO */ +	} else if (b43_is_cck_rate(bitrate) && phy->type != B43_PHYTYPE_LP) { +		control = bw; +	} else { +		control = bw; +		e = b43_tx_legacy_rate_phy_ctl_ent(bitrate); +		if (e) { +			control |= e->coding_rate; +			control |= e->modulation; +		} +		control |= B43_TXH_PHY1_MODE_SISO; +	} + +	return control; +} +  static u8 b43_calc_fallback_rate(u8 bitrate)  {  	switch (bitrate) { @@ -198,6 +257,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	unsigned int plcp_fragment_len;  	u32 mac_ctl = 0;  	u16 phy_ctl = 0; +	bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP || +			      phy->type == B43_PHYTYPE_N || +			      phy->type == B43_PHYTYPE_HT);  	u8 extra_ft = 0;  	struct ieee80211_rate *txrate;  	struct ieee80211_tx_rate *rates; @@ -216,7 +278,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	else  		txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);  	txhdr->mac_frame_ctl = wlhdr->frame_control; -	memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); +	memcpy(txhdr->tx_receiver, wlhdr->addr1, ETH_ALEN);  	/* Calculate duration for fallback rate */  	if ((rate_fb == rate) || @@ -228,7 +290,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		txhdr->dur_fb = wlhdr->duration_id;  	} else {  		txhdr->dur_fb = ieee80211_generic_frame_duration( -			dev->wl->hw, info->control.vif, fragment_len, fbrate); +			dev->wl->hw, info->control.vif, info->band, +			fragment_len, fbrate);  	}  	plcp_fragment_len = fragment_len + FCS_LEN; @@ -265,8 +328,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  			/* we give the phase1key and iv16 here, the key is stored in  			 * shm. With that the hardware can do phase 2 and encryption.  			 */ -			ieee80211_get_tkip_key(info->control.hw_key, skb_frag, -					IEEE80211_TKIP_P1_KEY, (u8*)phase1key); +			ieee80211_get_tkip_p1k(info->control.hw_key, skb_frag, phase1key);  			/* phase1key is in host endian. Copy to little-endian txhdr->iv. */  			for (i = 0; i < 5; i++) {  				txhdr->iv[i * 2 + 0] = phase1key[i]; @@ -275,17 +337,24 @@ int b43_generate_txhdr(struct b43_wldev *dev,  			/* iv16 */  			memcpy(txhdr->iv + 10, ((u8 *) wlhdr) + wlhdr_len, 3);  		} else { -			iv_len = min((size_t) info->control.hw_key->iv_len, +			iv_len = min_t(size_t, info->control.hw_key->iv_len,  				     ARRAY_SIZE(txhdr->iv));  			memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);  		}  	} -	if (b43_is_old_txhdr_format(dev)) { -		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), +	switch (dev->fw.hdr_format) { +	case B43_FW_HDR_598: +		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp),  				      plcp_fragment_len, rate); -	} else { -		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp), +		break; +	case B43_FW_HDR_351: +		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp), +				      plcp_fragment_len, rate); +		break; +	case B43_FW_HDR_410: +		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp),  				      plcp_fragment_len, rate); +		break;  	}  	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),  			      plcp_fragment_len, rate_fb); @@ -310,7 +379,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)  		phy_ctl |= B43_TXH_PHY_SHORTPRMBL; -	switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { +	switch (b43_ieee80211_antenna_sanitize(dev, 0)) {  	case 0: /* Default */  		phy_ctl |= B43_TXH_PHY_ANT01AUTO;  		break; @@ -339,7 +408,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		mac_ctl |= B43_TXH_MAC_HWSEQ;  	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)  		mac_ctl |= B43_TXH_MAC_STMSDU; -	if (phy->type == B43_PHYTYPE_A) +	if (!phy->gmode)  		mac_ctl |= B43_TXH_MAC_5GHZ;  	/* Overwrite rates[0].count to make the retry calculation @@ -358,10 +427,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||  	    (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {  		unsigned int len; -		struct ieee80211_hdr *hdr; +		struct ieee80211_hdr *uninitialized_var(hdr);  		int rts_rate, rts_rate_fb;  		int rts_rate_ofdm, rts_rate_fb_ofdm; -		struct b43_plcp_hdr6 *plcp; +		struct b43_plcp_hdr6 *uninitialized_var(plcp);  		struct ieee80211_rate *rts_cts_rate;  		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); @@ -372,14 +441,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);  		if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { -			struct ieee80211_cts *cts; +			struct ieee80211_cts *uninitialized_var(cts); -			if (b43_is_old_txhdr_format(dev)) { +			switch (dev->fw.hdr_format) { +			case B43_FW_HDR_598:  				cts = (struct ieee80211_cts *) -					(txhdr->old_format.rts_frame); -			} else { +					(txhdr->format_598.rts_frame); +				break; +			case B43_FW_HDR_351: +				cts = (struct ieee80211_cts *) +					(txhdr->format_351.rts_frame); +				break; +			case B43_FW_HDR_410:  				cts = (struct ieee80211_cts *) -					(txhdr->new_format.rts_frame); +					(txhdr->format_410.rts_frame); +				break;  			}  			ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,  						fragment_data, fragment_len, @@ -387,14 +463,21 @@ int b43_generate_txhdr(struct b43_wldev *dev,  			mac_ctl |= B43_TXH_MAC_SENDCTS;  			len = sizeof(struct ieee80211_cts);  		} else { -			struct ieee80211_rts *rts; +			struct ieee80211_rts *uninitialized_var(rts); -			if (b43_is_old_txhdr_format(dev)) { +			switch (dev->fw.hdr_format) { +			case B43_FW_HDR_598:  				rts = (struct ieee80211_rts *) -					(txhdr->old_format.rts_frame); -			} else { +					(txhdr->format_598.rts_frame); +				break; +			case B43_FW_HDR_351: +				rts = (struct ieee80211_rts *) +					(txhdr->format_351.rts_frame); +				break; +			case B43_FW_HDR_410:  				rts = (struct ieee80211_rts *) -					(txhdr->new_format.rts_frame); +					(txhdr->format_410.rts_frame); +				break;  			}  			ieee80211_rts_get(dev->wl->hw, info->control.vif,  					  fragment_data, fragment_len, @@ -405,22 +488,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		len += FCS_LEN;  		/* 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; +		switch (dev->fw.hdr_format) { +		case B43_FW_HDR_598: +			plcp = &txhdr->format_598.rts_plcp; +			break; +		case B43_FW_HDR_351: +			plcp = &txhdr->format_351.rts_plcp; +			break; +		case B43_FW_HDR_410: +			plcp = &txhdr->format_410.rts_plcp; +			break; +		}  		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); -		if (b43_is_old_txhdr_format(dev)) { +		switch (dev->fw.hdr_format) { +		case B43_FW_HDR_598:  			hdr = (struct ieee80211_hdr *) -				(&txhdr->old_format.rts_frame); -		} else { +				(&txhdr->format_598.rts_frame); +			break; +		case B43_FW_HDR_351: +			hdr = (struct ieee80211_hdr *) +				(&txhdr->format_351.rts_frame); +			break; +		case B43_FW_HDR_410:  			hdr = (struct ieee80211_hdr *) -				(&txhdr->new_format.rts_frame); +				(&txhdr->format_410.rts_frame); +			break;  		}  		txhdr->rts_dur_fb = hdr->duration_id; @@ -437,13 +534,35 @@ int b43_generate_txhdr(struct b43_wldev *dev,  			extra_ft |= B43_TXH_EFT_RTSFB_OFDM;  		else  			extra_ft |= B43_TXH_EFT_RTSFB_CCK; + +		if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS && +		    fill_phy_ctl1) { +			txhdr->phy_ctl1_rts = cpu_to_le16( +				b43_generate_tx_phy_ctl1(dev, rts_rate)); +			txhdr->phy_ctl1_rts_fb = cpu_to_le16( +				b43_generate_tx_phy_ctl1(dev, rts_rate_fb)); +		}  	}  	/* Magic 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); +	switch (dev->fw.hdr_format) { +	case B43_FW_HDR_598: +		txhdr->format_598.cookie = cpu_to_le16(cookie); +		break; +	case B43_FW_HDR_351: +		txhdr->format_351.cookie = cpu_to_le16(cookie); +		break; +	case B43_FW_HDR_410: +		txhdr->format_410.cookie = cpu_to_le16(cookie); +		break; +	} + +	if (fill_phy_ctl1) { +		txhdr->phy_ctl1 = +			cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate)); +		txhdr->phy_ctl1_fb = +			cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate_fb)); +	}  	/* Apply the bitfields */  	txhdr->mac_ctl = cpu_to_le32(mac_ctl); @@ -474,7 +593,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,  			else  				tmp -= 3;  		} else { -			if (dev->dev->bus->sprom. +			if (dev->dev->bus_sprom->  			    boardflags_lo & B43_BFL_RSSI) {  				if (in_rssi > 63)  					in_rssi = 63; @@ -539,20 +658,31 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  	struct ieee80211_hdr *wlhdr;  	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;  	__le16 fctl; -	u16 phystat0, phystat3, chanstat, mactime; -	u32 macstat; +	u16 phystat0, phystat3; +	u16 uninitialized_var(chanstat), uninitialized_var(mactime); +	u32 uninitialized_var(macstat);  	u16 chanid;  	u16 phytype; -	int padding; +	int padding, rate_idx;  	memset(&status, 0, sizeof(status));  	/* Get metadata about the frame from the header. */  	phystat0 = le16_to_cpu(rxhdr->phy_status0);  	phystat3 = le16_to_cpu(rxhdr->phy_status3); -	macstat = le32_to_cpu(rxhdr->mac_status); -	mactime = le16_to_cpu(rxhdr->mac_time); -	chanstat = le16_to_cpu(rxhdr->channel); +	switch (dev->fw.hdr_format) { +	case B43_FW_HDR_598: +		macstat = le32_to_cpu(rxhdr->format_598.mac_status); +		mactime = le16_to_cpu(rxhdr->format_598.mac_time); +		chanstat = le16_to_cpu(rxhdr->format_598.channel); +		break; +	case B43_FW_HDR_410: +	case B43_FW_HDR_351: +		macstat = le32_to_cpu(rxhdr->format_351.mac_status); +		mactime = le16_to_cpu(rxhdr->format_351.mac_time); +		chanstat = le16_to_cpu(rxhdr->format_351.channel); +		break; +	}  	phytype = chanstat & B43_RX_CHAN_PHYTYPE;  	if (unlikely(macstat & B43_RX_MAC_FCSERR)) { @@ -610,29 +740,43 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  	}  	/* Link quality statistics */ -	if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) { -//		s8 rssi = max(rxhdr->power0, rxhdr->power1); -		//TODO: Find out what the rssi value is (dBm or percentage?) -		//      and also find out what the maximum possible value is. -		//      Fill status.ssi and status.signal fields. -	} else { +	switch (chanstat & B43_RX_CHAN_PHYTYPE) { +	case B43_PHYTYPE_HT: +		/* TODO: is max the right choice? */ +		status.signal = max_t(__s8, +			max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1), +			rxhdr->phy_ht_power2); +		break; +	case B43_PHYTYPE_N: +		/* Broadcom has code for min and avg, but always uses max */ +		if (rxhdr->power0 == 16 || rxhdr->power0 == 32) +			status.signal = max(rxhdr->power1, rxhdr->power2); +		else +			status.signal = max(rxhdr->power0, rxhdr->power1); +		break; +	case B43_PHYTYPE_A: +	case B43_PHYTYPE_B: +	case B43_PHYTYPE_G: +	case B43_PHYTYPE_LP:  		status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,  						  (phystat0 & B43_RX_PHYST0_OFDM),  						  (phystat0 & B43_RX_PHYST0_GAINCTL),  						  (phystat3 & B43_RX_PHYST3_TRSTATE)); +		break;  	}  	if (phystat0 & B43_RX_PHYST0_OFDM) -		status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, +		rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,  						phytype == B43_PHYTYPE_A);  	else -		status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); -	if (unlikely(status.rate_idx == -1)) { +		rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); +	if (unlikely(rate_idx == -1)) {  		/* PLCP seems to be corrupted.  		 * Drop the frame, if we are not interested in corrupted frames. */  		if (!(dev->wl->filter_flags & FIF_PLCPFAIL))  			goto drop;  	} +	status.rate_idx = rate_idx;  	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);  	/* @@ -652,7 +796,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  		status.mactime += mactime;  		if (low_mactime_now <= mactime)  			status.mactime -= 0x10000; -		status.flag |= RX_FLAG_TSFT; +		status.flag |= RX_FLAG_MACTIME_START;  	}  	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; @@ -662,25 +806,30 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  		B43_WARN_ON(1);  		/* FIXME: We don't really know which value the "chanid" contains.  		 *        So the following assignment might be wrong. */ -		status.freq = b43_channel_to_freq_5ghz(chanid); +		status.freq = +			ieee80211_channel_to_frequency(chanid, status.band);  		break;  	case B43_PHYTYPE_G:  		status.band = IEEE80211_BAND_2GHZ; -		/* chanid is the radio channel cookie value as used -		 * to tune the radio. */ -		status.freq = chanid + 2400; +		/* Somewhere between 478.104 and 508.1084 firmware for G-PHY +		 * has been modified to be compatible with N-PHY and others. +		 */ +		if (dev->fw.rev >= 508) +			status.freq = ieee80211_channel_to_frequency(chanid, status.band); +		else +			status.freq = chanid + 2400;  		break;  	case B43_PHYTYPE_N:  	case B43_PHYTYPE_LP: +	case B43_PHYTYPE_HT:  		/* chanid is the SHM channel cookie. Which is the plain  		 * channel number in b43. */ -		if (chanstat & B43_RX_CHAN_5GHZ) { +		if (chanstat & B43_RX_CHAN_5GHZ)  			status.band = IEEE80211_BAND_5GHZ; -			status.freq = b43_freq_to_channel_5ghz(chanid); -		} else { +		else  			status.band = IEEE80211_BAND_2GHZ; -			status.freq = b43_freq_to_channel_2ghz(chanid); -		} +		status.freq = +			ieee80211_channel_to_frequency(chanid, status.band);  		break;  	default:  		B43_WARN_ON(1); @@ -695,7 +844,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  #endif  	return;  drop: -	b43dbg(dev->wl, "RX: Packet dropped\n");  	dev_kfree_skb_any(skb);  } @@ -732,7 +880,7 @@ bool b43_fill_txstatus_report(struct b43_wldev *dev,  			      struct ieee80211_tx_info *report,  			      const struct b43_txstatus *status)  { -	bool frame_success = 1; +	bool frame_success = true;  	int retry_limit;  	/* preserve the confiured retry limit before clearing the status @@ -748,7 +896,7 @@ bool b43_fill_txstatus_report(struct b43_wldev *dev,  		/* The frame was not ACKed... */  		if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {  			/* ...but we expected an ACK. */ -			frame_success = 0; +			frame_success = false;  		}  	}  	if (status->frame_count == 0) {  | 
