diff options
| -rw-r--r-- | package/b43/Makefile | 2 | ||||
| -rw-r--r-- | package/b43/src/Makefile | 5 | ||||
| -rw-r--r-- | package/b43/src/b43.h | 246 | ||||
| -rw-r--r-- | package/b43/src/debugfs.c | 81 | ||||
| -rw-r--r-- | package/b43/src/debugfs.h | 1 | ||||
| -rw-r--r-- | package/b43/src/dma.c | 595 | ||||
| -rw-r--r-- | package/b43/src/dma.h | 17 | ||||
| -rw-r--r-- | package/b43/src/leds.c | 8 | ||||
| -rw-r--r-- | package/b43/src/lo.c | 731 | ||||
| -rw-r--r-- | package/b43/src/lo.h | 115 | ||||
| -rw-r--r-- | package/b43/src/main.c | 1252 | ||||
| -rw-r--r-- | package/b43/src/main.h | 14 | ||||
| -rw-r--r-- | package/b43/src/nphy.c | 3 | ||||
| -rw-r--r-- | package/b43/src/nphy.h | 40 | ||||
| -rw-r--r-- | package/b43/src/pcmcia.c | 16 | ||||
| -rw-r--r-- | package/b43/src/phy.c | 295 | ||||
| -rw-r--r-- | package/b43/src/phy.h | 16 | ||||
| -rw-r--r-- | package/b43/src/pio.c | 842 | ||||
| -rw-r--r-- | package/b43/src/pio.h | 216 | ||||
| -rw-r--r-- | package/b43/src/wa.c | 45 | ||||
| -rw-r--r-- | package/b43/src/xmit.c | 177 | ||||
| -rw-r--r-- | package/b43/src/xmit.h | 46 | 
22 files changed, 3090 insertions, 1673 deletions
| diff --git a/package/b43/Makefile b/package/b43/Makefile index 3d5eb264c..6616585e2 100644 --- a/package/b43/Makefile +++ b/package/b43/Makefile @@ -44,6 +44,8 @@ endef  EXTRA_KCONFIG:= \  	CONFIG_B43=m \  	CONFIG_B43_NPHY=y \ +	CONFIG_B43_DEBUG=y \ +	$(if $(CONFIG_RFKILL),CONFIG_B43_RFKILL=y) \  	$(if $(CONFIG_LEDS_TRIGGERS),CONFIG_B43_LEDS=y) \ diff --git a/package/b43/src/Makefile b/package/b43/src/Makefile index ac1329dba..8c52b0b98 100644 --- a/package/b43/src/Makefile +++ b/package/b43/src/Makefile @@ -1,13 +1,14 @@  b43-y				+= main.o  b43-y				+= tables.o -b43-y				+= tables_nphy.o +b43-$(CONFIG_B43_NPHY)		+= tables_nphy.o  b43-y				+= phy.o -b43-y				+= nphy.o +b43-$(CONFIG_B43_NPHY)		+= nphy.o  b43-y				+= sysfs.o  b43-y				+= xmit.o  b43-y				+= lo.o  b43-y				+= wa.o  b43-y				+= dma.o +b43-$(CONFIG_B43_PIO)		+= pio.o  b43-$(CONFIG_B43_RFKILL)	+= rfkill.o  b43-$(CONFIG_B43_LEDS)		+= leds.o  b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o diff --git a/package/b43/src/b43.h b/package/b43/src/b43.h index 0dc1aaf46..e91918991 100644 --- a/package/b43/src/b43.h +++ b/package/b43/src/b43.h @@ -14,6 +14,12 @@  #include "lo.h"  #include "phy.h" + +/* The unique identifier of the firmware that's officially supported by + * this driver version. */ +#define B43_SUPPORTED_FIRMWARE_ID	"FW13" + +  #ifdef CONFIG_B43_DEBUG  # define B43_DEBUG	1  #else @@ -69,6 +75,23 @@  #define B43_MMIO_DMA64_BASE4		0x300  #define B43_MMIO_DMA64_BASE5		0x340 +/* PIO on core rev < 11 */ +#define B43_MMIO_PIO_BASE0		0x300 +#define B43_MMIO_PIO_BASE1		0x310 +#define B43_MMIO_PIO_BASE2		0x320 +#define B43_MMIO_PIO_BASE3		0x330 +#define B43_MMIO_PIO_BASE4		0x340 +#define B43_MMIO_PIO_BASE5		0x350 +#define B43_MMIO_PIO_BASE6		0x360 +#define B43_MMIO_PIO_BASE7		0x370 +/* PIO on core rev >= 11 */ +#define B43_MMIO_PIO11_BASE0		0x200 +#define B43_MMIO_PIO11_BASE1		0x240 +#define B43_MMIO_PIO11_BASE2		0x280 +#define B43_MMIO_PIO11_BASE3		0x2C0 +#define B43_MMIO_PIO11_BASE4		0x300 +#define B43_MMIO_PIO11_BASE5		0x340 +  #define B43_MMIO_PHY_VER		0x3E0  #define B43_MMIO_PHY_RADIO		0x3E2  #define B43_MMIO_PHY0			0x3E6 @@ -88,11 +111,14 @@  #define B43_MMIO_GPIO_MASK		0x49E  #define B43_MMIO_TSF_CFP_START_LOW	0x604  #define B43_MMIO_TSF_CFP_START_HIGH	0x606 +#define B43_MMIO_TSF_CFP_PRETBTT	0x612  #define B43_MMIO_TSF_0			0x632	/* core rev < 3 only */  #define B43_MMIO_TSF_1			0x634	/* core rev < 3 only */  #define B43_MMIO_TSF_2			0x636	/* core rev < 3 only */  #define B43_MMIO_TSF_3			0x638	/* core rev < 3 only */  #define B43_MMIO_RNG			0x65A +#define B43_MMIO_IFSCTL			0x688 /* Interframe space control */ +#define  B43_MMIO_IFSCTL_USE_EDCF	0x0004  #define B43_MMIO_POWERUP_DELAY		0x6A8  /* SPROM boardflags_lo values */ @@ -138,7 +164,8 @@ enum {  #define B43_SHM_SH_PHYTYPE		0x0052	/* PHY type */  #define B43_SHM_SH_ANTSWAP		0x005C	/* Antenna swap threshold */  #define B43_SHM_SH_HOSTFLO		0x005E	/* Hostflags for ucode options (low) */ -#define B43_SHM_SH_HOSTFHI		0x0060	/* Hostflags for ucode options (high) */ +#define B43_SHM_SH_HOSTFMI		0x0060	/* Hostflags for ucode options (middle) */ +#define B43_SHM_SH_HOSTFHI		0x0062	/* Hostflags for ucode options (high) */  #define B43_SHM_SH_RFATT		0x0064	/* Current radio attenuation value */  #define B43_SHM_SH_RADAR		0x0066	/* Radar register */  #define B43_SHM_SH_PHYTXNOI		0x006E	/* PHY noise directly after TX (lower 8bit only) */ @@ -226,31 +253,41 @@ enum {  #define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)  /* HostFlags. See b43_hf_read/write() */ -#define B43_HF_ANTDIVHELP		0x00000001	/* ucode antenna div helper */ -#define B43_HF_SYMW			0x00000002	/* G-PHY SYM workaround */ -#define B43_HF_RXPULLW			0x00000004	/* RX pullup workaround */ -#define B43_HF_CCKBOOST			0x00000008	/* 4dB CCK power boost (exclusive with OFDM boost) */ -#define B43_HF_BTCOEX			0x00000010	/* Bluetooth coexistance */ -#define B43_HF_GDCW			0x00000020	/* G-PHY DV canceller filter bw workaround */ -#define B43_HF_OFDMPABOOST		0x00000040	/* Enable PA gain boost for OFDM */ -#define B43_HF_ACPR			0x00000080	/* Disable for Japan, channel 14 */ -#define B43_HF_EDCF			0x00000100	/* on if WME and MAC suspended */ -#define B43_HF_TSSIRPSMW		0x00000200	/* TSSI reset PSM ucode workaround */ -#define B43_HF_DSCRQ			0x00000400	/* Disable slow clock request in ucode */ -#define B43_HF_ACIW			0x00000800	/* ACI workaround: shift bits by 2 on PHY CRS */ -#define B43_HF_2060W			0x00001000	/* 2060 radio workaround */ -#define B43_HF_RADARW			0x00002000	/* Radar workaround */ -#define B43_HF_USEDEFKEYS		0x00004000	/* Enable use of default keys */ -#define B43_HF_BT4PRIOCOEX		0x00010000	/* Bluetooth 2-priority coexistance */ -#define B43_HF_FWKUP			0x00020000	/* Fast wake-up ucode */ -#define B43_HF_VCORECALC		0x00040000	/* Force VCO recalculation when powering up synthpu */ -#define B43_HF_PCISCW			0x00080000	/* PCI slow clock workaround */ -#define B43_HF_4318TSSI			0x00200000	/* 4318 TSSI */ -#define B43_HF_FBCMCFIFO		0x00400000	/* Flush bcast/mcast FIFO immediately */ -#define B43_HF_HWPCTL			0x00800000	/* Enable hardwarre power control */ -#define B43_HF_BTCOEXALT		0x01000000	/* Bluetooth coexistance in alternate pins */ -#define B43_HF_TXBTCHECK		0x02000000	/* Bluetooth check during transmission */ -#define B43_HF_SKCFPUP			0x04000000	/* Skip CFP update */ +#define B43_HF_ANTDIVHELP	0x000000000001ULL /* ucode antenna div helper */ +#define B43_HF_SYMW		0x000000000002ULL /* G-PHY SYM workaround */ +#define B43_HF_RXPULLW		0x000000000004ULL /* RX pullup workaround */ +#define B43_HF_CCKBOOST		0x000000000008ULL /* 4dB CCK power boost (exclusive with OFDM boost) */ +#define B43_HF_BTCOEX		0x000000000010ULL /* Bluetooth coexistance */ +#define B43_HF_GDCW		0x000000000020ULL /* G-PHY DC canceller filter bw workaround */ +#define B43_HF_OFDMPABOOST	0x000000000040ULL /* Enable PA gain boost for OFDM */ +#define B43_HF_ACPR		0x000000000080ULL /* Disable for Japan, channel 14 */ +#define B43_HF_EDCF		0x000000000100ULL /* on if WME and MAC suspended */ +#define B43_HF_TSSIRPSMW	0x000000000200ULL /* TSSI reset PSM ucode workaround */ +#define B43_HF_20IN40IQW	0x000000000200ULL /* 20 in 40 MHz I/Q workaround (rev >= 13 only) */ +#define B43_HF_DSCRQ		0x000000000400ULL /* Disable slow clock request in ucode */ +#define B43_HF_ACIW		0x000000000800ULL /* ACI workaround: shift bits by 2 on PHY CRS */ +#define B43_HF_2060W		0x000000001000ULL /* 2060 radio workaround */ +#define B43_HF_RADARW		0x000000002000ULL /* Radar workaround */ +#define B43_HF_USEDEFKEYS	0x000000004000ULL /* Enable use of default keys */ +#define B43_HF_AFTERBURNER	0x000000008000ULL /* Afterburner enabled */ +#define B43_HF_BT4PRIOCOEX	0x000000010000ULL /* Bluetooth 4-priority coexistance */ +#define B43_HF_FWKUP		0x000000020000ULL /* Fast wake-up ucode */ +#define B43_HF_VCORECALC	0x000000040000ULL /* Force VCO recalculation when powering up synthpu */ +#define B43_HF_PCISCW		0x000000080000ULL /* PCI slow clock workaround */ +#define B43_HF_4318TSSI		0x000000200000ULL /* 4318 TSSI */ +#define B43_HF_FBCMCFIFO	0x000000400000ULL /* Flush bcast/mcast FIFO immediately */ +#define B43_HF_HWPCTL		0x000000800000ULL /* Enable hardwarre power control */ +#define B43_HF_BTCOEXALT	0x000001000000ULL /* Bluetooth coexistance in alternate pins */ +#define B43_HF_TXBTCHECK	0x000002000000ULL /* Bluetooth check during transmission */ +#define B43_HF_SKCFPUP		0x000004000000ULL /* Skip CFP update */ +#define B43_HF_N40W		0x000008000000ULL /* N PHY 40 MHz workaround (rev >= 13 only) */ +#define B43_HF_ANTSEL		0x000020000000ULL /* Antenna selection (for testing antenna div.) */ +#define B43_HF_BT3COEXT		0x000020000000ULL /* Bluetooth 3-wire coexistence (rev >= 13 only) */ +#define B43_HF_BTCANT		0x000040000000ULL /* Bluetooth coexistence (antenna mode) (rev >= 13 only) */ +#define B43_HF_ANTSELEN		0x000100000000ULL /* Antenna selection enabled (rev >= 13 only) */ +#define B43_HF_ANTSELMODE	0x000200000000ULL /* Antenna selection mode (rev >= 13 only) */ +#define B43_HF_MLADVW		0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */ +#define B43_HF_PR45960W		0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */  /* MacFilter offsets. */  #define B43_MACFILTER_SELF		0x0000 @@ -373,9 +410,7 @@ enum {  #define B43_IRQ_TIMEOUT			0x80000000  #define B43_IRQ_ALL			0xFFFFFFFF -#define B43_IRQ_MASKTEMPLATE		(B43_IRQ_MAC_SUSPENDED | \ -					 B43_IRQ_BEACON | \ -					 B43_IRQ_TBTT_INDI | \ +#define B43_IRQ_MASKTEMPLATE		(B43_IRQ_TBTT_INDI | \  					 B43_IRQ_ATIM_END | \  					 B43_IRQ_PMQ | \  					 B43_IRQ_MAC_TXERR | \ @@ -387,6 +422,26 @@ enum {  					 B43_IRQ_RFKILL | \  					 B43_IRQ_TX_OK) +/* The firmware register to fetch the debug-IRQ reason from. */ +#define B43_DEBUGIRQ_REASON_REG		63 +/* Debug-IRQ reasons. */ +#define B43_DEBUGIRQ_PANIC		0	/* The firmware panic'ed */ +#define B43_DEBUGIRQ_DUMP_SHM		1	/* Dump shared SHM */ +#define B43_DEBUGIRQ_DUMP_REGS		2	/* Dump the microcode registers */ +#define B43_DEBUGIRQ_MARKER		3	/* A "marker" was thrown by the firmware. */ +#define B43_DEBUGIRQ_ACK		0xFFFF	/* The host writes that to ACK the IRQ */ + +/* The firmware register that contains the "marker" line. */ +#define B43_MARKER_ID_REG		2 +#define B43_MARKER_LINE_REG		3 + +/* The firmware register to fetch the panic reason from. */ +#define B43_FWPANIC_REASON_REG		3 +/* Firmware panic reason codes */ +#define B43_FWPANIC_DIE			0 /* Firmware died. Don't auto-restart it. */ +#define B43_FWPANIC_RESTART		1 /* Firmware died. Schedule a controller reset. */ + +  /* Device specific rate values.   * The actual values defined here are (rate_in_mbps * 2).   * Some code depends on this. Don't change it. */ @@ -423,7 +478,6 @@ enum {  };  struct b43_dmaring; -struct b43_pioqueue;  /* The firmware file header */  #define B43_FW_TYPE_UCODE	'u' @@ -452,14 +506,11 @@ struct b43_iv {  } __attribute__((__packed__)); -#define B43_PHYMODE(phytype)		(1 << (phytype)) -#define B43_PHYMODE_A			B43_PHYMODE(B43_PHYTYPE_A) -#define B43_PHYMODE_B			B43_PHYMODE(B43_PHYTYPE_B) -#define B43_PHYMODE_G			B43_PHYMODE(B43_PHYTYPE_G) -  struct b43_phy { -	/* Possible PHYMODEs on this PHY */ -	u8 possible_phymodes; +	/* Band support flags. */ +	bool supports_2ghz; +	bool supports_5ghz; +  	/* GMODE bit enabled? */  	bool gmode; @@ -573,15 +624,27 @@ struct b43_phy {  /* Data structures for DMA transmission, per 80211 core. */  struct b43_dma { -	struct b43_dmaring *tx_ring0; -	struct b43_dmaring *tx_ring1; -	struct b43_dmaring *tx_ring2; -	struct b43_dmaring *tx_ring3; -	struct b43_dmaring *tx_ring4; -	struct b43_dmaring *tx_ring5; - -	struct b43_dmaring *rx_ring0; -	struct b43_dmaring *rx_ring3;	/* only available on core.rev < 5 */ +	struct b43_dmaring *tx_ring_AC_BK; /* Background */ +	struct b43_dmaring *tx_ring_AC_BE; /* Best Effort */ +	struct b43_dmaring *tx_ring_AC_VI; /* Video */ +	struct b43_dmaring *tx_ring_AC_VO; /* Voice */ +	struct b43_dmaring *tx_ring_mcast; /* Multicast */ + +	struct b43_dmaring *rx_ring; +}; + +struct b43_pio_txqueue; +struct b43_pio_rxqueue; + +/* Data structures for PIO transmission, per 80211 core. */ +struct b43_pio { +	struct b43_pio_txqueue *tx_queue_AC_BK; /* Background */ +	struct b43_pio_txqueue *tx_queue_AC_BE; /* Best Effort */ +	struct b43_pio_txqueue *tx_queue_AC_VI; /* Video */ +	struct b43_pio_txqueue *tx_queue_AC_VO; /* Voice */ +	struct b43_pio_txqueue *tx_queue_mcast; /* Multicast */ + +	struct b43_pio_rxqueue *rx_queue;  };  /* Context information for a noise calculation (Link Quality). */ @@ -607,6 +670,35 @@ struct b43_key {  	u8 algorithm;  }; +/* SHM offsets to the QOS data structures for the 4 different queues. */ +#define B43_QOS_PARAMS(queue)	(B43_SHM_SH_EDCFQ + \ +				 (B43_NR_QOSPARAMS * sizeof(u16) * (queue))) +#define B43_QOS_BACKGROUND	B43_QOS_PARAMS(0) +#define B43_QOS_BESTEFFORT	B43_QOS_PARAMS(1) +#define B43_QOS_VIDEO		B43_QOS_PARAMS(2) +#define B43_QOS_VOICE		B43_QOS_PARAMS(3) + +/* QOS parameter hardware data structure offsets. */ +#define B43_NR_QOSPARAMS	22 +enum { +	B43_QOSPARAM_TXOP = 0, +	B43_QOSPARAM_CWMIN, +	B43_QOSPARAM_CWMAX, +	B43_QOSPARAM_CWCUR, +	B43_QOSPARAM_AIFS, +	B43_QOSPARAM_BSLOTS, +	B43_QOSPARAM_REGGAP, +	B43_QOSPARAM_STATUS, +}; + +/* QOS parameters for a queue. */ +struct b43_qos_params { +	/* The QOS parameters */ +	struct ieee80211_tx_queue_params p; +	/* Does this need to get uploaded to hardware? */ +	bool need_hw_update; +}; +  struct b43_wldev;  /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ @@ -618,6 +710,10 @@ struct b43_wl {  	struct mutex mutex;  	spinlock_t irq_lock; +	/* R/W lock for data transmission. +	 * Transmissions on 2+ queues can run concurrently, but somebody else +	 * might sync with TX by write_lock_irqsave()'ing. */ +	rwlock_t tx_lock;  	/* Lock for LEDs access. */  	spinlock_t leds_lock;  	/* Lock for SHM access. */ @@ -659,6 +755,13 @@ struct b43_wl {  	struct sk_buff *current_beacon;  	bool beacon0_uploaded;  	bool beacon1_uploaded; +	struct work_struct beacon_update_trigger; + +	/* The current QOS parameters for the 4 queues. +	 * This is protected by the irq_lock. */ +	struct b43_qos_params qos_params[4]; +	/* Workqueue for updating QOS parameters in hardware. */ +	struct work_struct qos_update_work;  };  /* In-memory representation of a cached microcode file. */ @@ -682,6 +785,13 @@ struct b43_firmware {  	u16 rev;  	/* Firmware patchlevel */  	u16 patch; + +	/* Set to true, if we are using an opensource firmware. */ +	bool opensource; +	/* Set to true, if the core needs a PCM firmware, but +	 * we failed to load one. This is always false for +	 * core rev > 10, as these don't need PCM firmware. */ +	bool pcm_request_failed;  };  /* Device (802.11 core) initialization status. */ @@ -719,12 +829,20 @@ struct b43_wldev {  	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM) */  	bool short_slot;	/* TRUE, if short slot timing is enabled. */  	bool radio_hw_enable;	/* saved state of radio hardware enabled state */ +	bool suspend_in_progress;	/* TRUE, if we are in a suspend/resume cycle */  	/* PHY/Radio device. */  	struct b43_phy phy; -	/* DMA engines. */ -	struct b43_dma dma; +	union { +		/* DMA engines. */ +		struct b43_dma dma; +		/* PIO engines. */ +		struct b43_pio pio; +	}; +	/* Use b43_using_pio_transfers() to check whether we are using +	 * DMA or PIO data transfers. */ +	bool __using_pio_transfers;  	/* Various statistics about the physical device. */  	struct b43_stats stats; @@ -808,6 +926,22 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)  	ssb_write32(dev->dev, offset, value);  } +static inline bool b43_using_pio_transfers(struct b43_wldev *dev) +{ +#ifdef CONFIG_B43_PIO +	return dev->__using_pio_transfers; +#else +	return 0; +#endif +} + +#ifdef CONFIG_B43_FORCE_PIO +# define B43_FORCE_PIO	1 +#else +# define B43_FORCE_PIO	0 +#endif + +  /* Message printing */  void b43info(struct b43_wl *wl, const char *fmt, ...)      __attribute__ ((format(printf, 2, 3))); @@ -831,22 +965,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; }  # define B43_WARN_ON(x)	__b43_warn_on_dummy(unlikely(!!(x)))  #endif -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max)  \ -	({						\ -		typeof(value) __value = (value);	\ -		typeof(value) __min = (min);		\ -		typeof(value) __max = (max);		\ -		if (__value < __min)			\ -			__value = __min;		\ -		else if (__value > __max)		\ -			__value = __max;		\ -		__value;				\ -	}) -  /* Convert an integer to a Q5.2 value */  #define INT_TO_Q52(i)	((i) << 2)  /* Convert a Q5.2 value to an integer (precision loss!) */ diff --git a/package/b43/src/debugfs.c b/package/b43/src/debugfs.c index e38ed0fe7..210e2789c 100644 --- a/package/b43/src/debugfs.c +++ b/package/b43/src/debugfs.c @@ -270,24 +270,22 @@ static int restart_write_file(struct b43_wldev *dev,  	return err;  } -static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, -			       struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +static unsigned long calc_expire_secs(unsigned long now, +				      unsigned long time, +				      unsigned long expire)  { -	unsigned int i, j; -	struct b43_loctl *ctl; - -	for (i = 0; i < B43_NR_BB; i++) { -		for (j = 0; j < B43_NR_RF; j++) { -			ctl = &(table[i][j]); -			fappend("(bbatt %2u, rfatt %2u)  ->  " -				"(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", -				i, j, ctl->i, ctl->q, -				ctl->used, -				b43_loctl_is_calibrated(ctl)); -		} +	expire = time + expire; + +	if (time_after(now, expire)) +		return 0; /* expired */ +	if (expire < now) { +		/* jiffies wrapped */ +		expire -= MAX_JIFFY_OFFSET; +		now -= MAX_JIFFY_OFFSET;  	} +	B43_WARN_ON(expire < now); -	return count; +	return (expire - now) / HZ;  }  static ssize_t loctls_read_file(struct b43_wldev *dev, @@ -296,27 +294,45 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,  	ssize_t count = 0;  	struct b43_txpower_lo_control *lo;  	int i, err = 0; +	struct b43_lo_calib *cal; +	unsigned long now = jiffies; +	struct b43_phy *phy = &dev->phy; -	if (dev->phy.type != B43_PHYTYPE_G) { +	if (phy->type != B43_PHYTYPE_G) {  		fappend("Device is not a G-PHY\n");  		err = -ENODEV;  		goto out;  	} -	lo = dev->phy.lo_control; +	lo = phy->lo_control;  	fappend("-- Local Oscillator calibration data --\n\n"); -	fappend("Measured: %d,  Rebuild: %d,  HW-power-control: %d\n", -		lo->lo_measured, -		lo->rebuild, +	fappend("HW-power-control enabled: %d\n",  		dev->phy.hardware_power_control); -	fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X\n", -		lo->tx_bias, lo->tx_magn); -	fappend("Power Vector: 0x%08X%08X\n", +	fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X  (expire in %lu sec)\n", +		lo->tx_bias, lo->tx_magn, +		calc_expire_secs(now, lo->txctl_measured_time, +				 B43_LO_TXCTL_EXPIRE)); +	fappend("Power Vector: 0x%08X%08X  (expires in %lu sec)\n",  		(unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), -		(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); -	fappend("\nControl table WITH PADMIX:\n"); -	count = append_lo_table(count, buf, bufsize, lo->with_padmix); -	fappend("\nControl table WITHOUT PADMIX:\n"); -	count = append_lo_table(count, buf, bufsize, lo->no_padmix); +		(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL), +		calc_expire_secs(now, lo->pwr_vec_read_time, +				 B43_LO_PWRVEC_EXPIRE)); + +	fappend("\nCalibrated settings:\n"); +	list_for_each_entry(cal, &lo->calib_list, list) { +		bool active; + +		active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && +			  b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); +		fappend("BB(%d), RF(%d,%d)  ->  I=%d, Q=%d  " +			"(expires in %lu sec)%s\n", +			cal->bbatt.att, +			cal->rfatt.att, cal->rfatt.with_padmix, +			cal->ctl.i, cal->ctl.q, +			calc_expire_secs(now, cal->calib_time, +					 B43_LO_CALIB_EXPIRE), +			active ? "  ACTIVE" : ""); +	} +  	fappend("\nUsed RF attenuation values:  Value(WithPadmix flag)\n");  	for (i = 0; i < lo->rfatt_list.len; i++) {  		fappend("%u(%d), ", @@ -351,7 +367,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,  	struct b43_dfs_file *dfile;  	ssize_t uninitialized_var(ret);  	char *buf; -	const size_t bufsize = 1024 * 128; +	const size_t bufsize = 1024 * 16; /* 16 kiB buffer */  	const size_t buforder = get_order(bufsize);  	int err = 0; @@ -380,8 +396,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,  			err = -ENOMEM;  			goto out_unlock;  		} -		/* Sparse warns about the following memset, because it has a big -		 * size value. That warning is bogus, so I will ignore it. --mb */  		memset(buf, 0, bufsize);  		if (dfops->take_irqlock) {  			spin_lock_irq(&dev->wl->irq_lock); @@ -523,6 +537,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)  	add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);  	add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);  	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); +	add_dyn_dbg("debug_lo", B43_DBG_LO, 0);  #undef add_dyn_dbg  } @@ -618,6 +633,7 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)  	kfree(e);  } +/* Called with IRQs disabled. */  void b43_debugfs_log_txstat(struct b43_wldev *dev,  			    const struct b43_txstatus *status)  { @@ -629,8 +645,7 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,  	if (!e)  		return;  	log = &e->txstatlog; -	B43_WARN_ON(!irqs_disabled()); -	spin_lock(&log->lock); +	spin_lock(&log->lock); /* IRQs are already disabled. */  	i = log->end + 1;  	if (i == B43_NR_LOGGED_TXSTATUS)  		i = 0; diff --git a/package/b43/src/debugfs.h b/package/b43/src/debugfs.h index 6eebe858d..c75cff415 100644 --- a/package/b43/src/debugfs.h +++ b/package/b43/src/debugfs.h @@ -10,6 +10,7 @@ enum b43_dyndbg {		/* Dynamic debugging features */  	B43_DBG_DMAVERBOSE,  	B43_DBG_PWORK_FAST,  	B43_DBG_PWORK_STOP, +	B43_DBG_LO,  	__B43_NR_DYNDBG,  }; diff --git a/package/b43/src/dma.c b/package/b43/src/dma.c index 3dfb28a34..b4eadd908 100644 --- a/package/b43/src/dma.c +++ b/package/b43/src/dma.c @@ -38,6 +38,7 @@  #include <linux/delay.h>  #include <linux/skbuff.h>  #include <linux/etherdevice.h> +#include <asm/div64.h>  /* 32bit DMA ops. */ @@ -291,52 +292,6 @@ static inline int request_slot(struct b43_dmaring *ring)  	return slot;  } -/* Mac80211-queue to b43-ring mapping */ -static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, -					      int queue_priority) -{ -	struct b43_dmaring *ring; - -/*FIXME: For now we always run on TX-ring-1 */ -	return dev->dma.tx_ring1; - -	/* 0 = highest priority */ -	switch (queue_priority) { -	default: -		B43_WARN_ON(1); -		/* fallthrough */ -	case 0: -		ring = dev->dma.tx_ring3; -		break; -	case 1: -		ring = dev->dma.tx_ring2; -		break; -	case 2: -		ring = dev->dma.tx_ring1; -		break; -	case 3: -		ring = dev->dma.tx_ring0; -		break; -	} - -	return ring; -} - -/* b43-ring to mac80211-queue mapping */ -static inline int txring_to_priority(struct b43_dmaring *ring) -{ -	static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; -	unsigned int index; - -/*FIXME: have only one queue, for now */ -	return 0; - -	index = ring->index; -	if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) -		index = 0; -	return idx_to_prio[index]; -} -  static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)  {  	static const u16 map64[] = { @@ -373,10 +328,10 @@ static inline  	dma_addr_t dmaaddr;  	if (tx) { -		dmaaddr = dma_map_single(ring->dev->dev->dev, +		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,  					 buf, len, DMA_TO_DEVICE);  	} else { -		dmaaddr = dma_map_single(ring->dev->dev->dev, +		dmaaddr = dma_map_single(ring->dev->dev->dma_dev,  					 buf, len, DMA_FROM_DEVICE);  	} @@ -388,9 +343,10 @@ static inline  			  dma_addr_t addr, size_t len, int tx)  {  	if (tx) { -		dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE); +		dma_unmap_single(ring->dev->dev->dma_dev, +				 addr, len, DMA_TO_DEVICE);  	} else { -		dma_unmap_single(ring->dev->dev->dev, +		dma_unmap_single(ring->dev->dev->dma_dev,  				 addr, len, DMA_FROM_DEVICE);  	}  } @@ -400,7 +356,7 @@ static inline  				 dma_addr_t addr, size_t len)  {  	B43_WARN_ON(ring->tx); -	dma_sync_single_for_cpu(ring->dev->dev->dev, +	dma_sync_single_for_cpu(ring->dev->dev->dma_dev,  				addr, len, DMA_FROM_DEVICE);  } @@ -409,7 +365,7 @@ static inline  				    dma_addr_t addr, size_t len)  {  	B43_WARN_ON(ring->tx); -	dma_sync_single_for_device(ring->dev->dev->dev, +	dma_sync_single_for_device(ring->dev->dev->dma_dev,  				   addr, len, DMA_FROM_DEVICE);  } @@ -425,7 +381,7 @@ static inline  static int alloc_ringmemory(struct b43_dmaring *ring)  { -	struct device *dev = ring->dev->dev->dev; +	struct device *dma_dev = ring->dev->dev->dma_dev;  	gfp_t flags = GFP_KERNEL;  	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K @@ -439,7 +395,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)  	 */  	if (ring->type == B43_DMA_64BIT)  		flags |= GFP_DMA; -	ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, +	ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,  					    &(ring->dmabase), flags);  	if (!ring->descbase) {  		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); @@ -452,9 +408,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)  static void free_ringmemory(struct b43_dmaring *ring)  { -	struct device *dev = ring->dev->dev->dev; +	struct device *dma_dev = ring->dev->dev->dma_dev; -	dma_free_coherent(dev, B43_DMA_RINGMEMSIZE, +	dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,  			  ring->descbase, ring->dmabase);  } @@ -560,7 +516,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,  /* Check if a DMA mapping address is invalid. */  static bool b43_dma_mapping_error(struct b43_dmaring *ring,  				  dma_addr_t addr, -				  size_t buffersize) +				  size_t buffersize, bool dma_to_device)  {  	if (unlikely(dma_mapping_error(addr)))  		return 1; @@ -568,11 +524,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,  	switch (ring->type) {  	case B43_DMA_30BIT:  		if ((u64)addr + buffersize > (1ULL << 30)) -			return 1; +			goto address_error;  		break;  	case B43_DMA_32BIT:  		if ((u64)addr + buffersize > (1ULL << 32)) -			return 1; +			goto address_error;  		break;  	case B43_DMA_64BIT:  		/* Currently we can't have addresses beyond @@ -582,6 +538,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,  	/* The address is OK. */  	return 0; + +address_error: +	/* We can't support this address. Unmap it again. */ +	unmap_descbuffer(ring, addr, buffersize, dma_to_device); + +	return 1;  }  static int setup_rx_descbuffer(struct b43_dmaring *ring, @@ -589,7 +551,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,  			       struct b43_dmadesc_meta *meta, gfp_t gfp_flags)  {  	struct b43_rxhdr_fw4 *rxhdr; -	struct b43_hwtxstatus *txstat;  	dma_addr_t dmaaddr;  	struct sk_buff *skb; @@ -599,7 +560,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,  	if (unlikely(!skb))  		return -ENOMEM;  	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); -	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { +	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {  		/* ugh. try to realloc in zone_dma */  		gfp_flags |= GFP_DMA; @@ -612,7 +573,8 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,  					 ring->rx_buffersize, 0);  	} -	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { +	if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { +		b43err(ring->dev->wl, "RX DMA buffer allocation failed\n");  		dev_kfree_skb_any(skb);  		return -EIO;  	} @@ -624,8 +586,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,  	rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);  	rxhdr->frame_len = 0; -	txstat = (struct b43_hwtxstatus *)(skb->data); -	txstat->cookie = 0;  	return 0;  } @@ -814,6 +774,18 @@ static u64 supported_dma_mask(struct b43_wldev *dev)  	return DMA_30BIT_MASK;  } +static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask) +{ +	if (dmamask == DMA_30BIT_MASK) +		return B43_DMA_30BIT; +	if (dmamask == DMA_32BIT_MASK) +		return B43_DMA_32BIT; +	if (dmamask == DMA_64BIT_MASK) +		return B43_DMA_64BIT; +	B43_WARN_ON(1); +	return B43_DMA_30BIT; +} +  /* Main initialization function. */  static  struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, @@ -847,12 +819,13 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,  			goto err_kfree_meta;  		/* test for ability to dma to txhdr_cache */ -		dma_test = dma_map_single(dev->dev->dev, +		dma_test = dma_map_single(dev->dev->dma_dev,  					  ring->txhdr_cache,  					  b43_txhdr_size(dev),  					  DMA_TO_DEVICE); -		if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) { +		if (b43_dma_mapping_error(ring, dma_test, +					  b43_txhdr_size(dev), 1)) {  			/* ugh realloc */  			kfree(ring->txhdr_cache);  			ring->txhdr_cache = kcalloc(nr_slots, @@ -861,17 +834,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,  			if (!ring->txhdr_cache)  				goto err_kfree_meta; -			dma_test = dma_map_single(dev->dev->dev, +			dma_test = dma_map_single(dev->dev->dma_dev,  						  ring->txhdr_cache,  						  b43_txhdr_size(dev),  						  DMA_TO_DEVICE);  			if (b43_dma_mapping_error(ring, dma_test, -						  b43_txhdr_size(dev))) +						  b43_txhdr_size(dev), 1)) { + +				b43err(dev->wl, +				       "TXHDR DMA allocation failed\n");  				goto err_kfree_txhdr_cache; +			}  		} -		dma_unmap_single(dev->dev->dev, +		dma_unmap_single(dev->dev->dma_dev,  				 dma_test, b43_txhdr_size(dev),  				 DMA_TO_DEVICE);  	} @@ -924,16 +901,52 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,  	goto out;  } +#define divide(a, b)	({	\ +	typeof(a) __a = a;	\ +	do_div(__a, b);		\ +	__a;			\ +  }) + +#define modulo(a, b)	({	\ +	typeof(a) __a = a;	\ +	do_div(__a, b);		\ +  }) +  /* Main cleanup function. */ -static void b43_destroy_dmaring(struct b43_dmaring *ring) +static void b43_destroy_dmaring(struct b43_dmaring *ring, +				const char *ringname)  {  	if (!ring)  		return; -	b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n", -	       (unsigned int)(ring->type), -	       ring->mmio_base, -	       (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots); +#ifdef CONFIG_B43_DEBUG +	{ +		/* Print some statistics. */ +		u64 failed_packets = ring->nr_failed_tx_packets; +		u64 succeed_packets = ring->nr_succeed_tx_packets; +		u64 nr_packets = failed_packets + succeed_packets; +		u64 permille_failed = 0, average_tries = 0; + +		if (nr_packets) +			permille_failed = divide(failed_packets * 1000, nr_packets); +		if (nr_packets) +			average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets); + +		b43dbg(ring->dev->wl, "DMA-%u %s: " +		       "Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, " +		       "Average tries %llu.%02llu\n", +		       (unsigned int)(ring->type), ringname, +		       ring->max_used_slots, +		       ring->nr_slots, +		       (unsigned long long)failed_packets, +		       (unsigned long long)nr_packets, +		       (unsigned long long)divide(permille_failed, 10), +		       (unsigned long long)modulo(permille_failed, 10), +		       (unsigned long long)divide(average_tries, 100), +		       (unsigned long long)modulo(average_tries, 100)); +	} +#endif /* DEBUG */ +  	/* Device IRQs are disabled prior entering this function,  	 * so no need to take care of concurrency with rx handler stuff.  	 */ @@ -946,139 +959,129 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)  	kfree(ring);  } +#define destroy_ring(dma, ring) do {				\ +	b43_destroy_dmaring((dma)->ring, __stringify(ring));	\ +	(dma)->ring = NULL;					\ +    } while (0) +  void b43_dma_free(struct b43_wldev *dev)  { -	struct b43_dma *dma = &dev->dma; +	struct b43_dma *dma; -	b43_destroy_dmaring(dma->rx_ring3); -	dma->rx_ring3 = NULL; -	b43_destroy_dmaring(dma->rx_ring0); -	dma->rx_ring0 = NULL; - -	b43_destroy_dmaring(dma->tx_ring5); -	dma->tx_ring5 = NULL; -	b43_destroy_dmaring(dma->tx_ring4); -	dma->tx_ring4 = NULL; -	b43_destroy_dmaring(dma->tx_ring3); -	dma->tx_ring3 = NULL; -	b43_destroy_dmaring(dma->tx_ring2); -	dma->tx_ring2 = NULL; -	b43_destroy_dmaring(dma->tx_ring1); -	dma->tx_ring1 = NULL; -	b43_destroy_dmaring(dma->tx_ring0); -	dma->tx_ring0 = NULL; +	if (b43_using_pio_transfers(dev)) +		return; +	dma = &dev->dma; + +	destroy_ring(dma, rx_ring); +	destroy_ring(dma, tx_ring_AC_BK); +	destroy_ring(dma, tx_ring_AC_BE); +	destroy_ring(dma, tx_ring_AC_VI); +	destroy_ring(dma, tx_ring_AC_VO); +	destroy_ring(dma, tx_ring_mcast); +} + +static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) +{ +	u64 orig_mask = mask; +	bool fallback = 0; +	int err; + +	/* Try to set the DMA mask. If it fails, try falling back to a +	 * lower mask, as we can always also support a lower one. */ +	while (1) { +		err = ssb_dma_set_mask(dev->dev, mask); +		if (!err) +			break; +		if (mask == DMA_64BIT_MASK) { +			mask = DMA_32BIT_MASK; +			fallback = 1; +			continue; +		} +		if (mask == DMA_32BIT_MASK) { +			mask = DMA_30BIT_MASK; +			fallback = 1; +			continue; +		} +		b43err(dev->wl, "The machine/kernel does not support " +		       "the required %u-bit DMA mask\n", +		       (unsigned int)dma_mask_to_engine_type(orig_mask)); +		return -EOPNOTSUPP; +	} +	if (fallback) { +		b43info(dev->wl, "DMA mask fallback from %u-bit to %u-bit\n", +			(unsigned int)dma_mask_to_engine_type(orig_mask), +			(unsigned int)dma_mask_to_engine_type(mask)); +	} + +	return 0;  }  int b43_dma_init(struct b43_wldev *dev)  {  	struct b43_dma *dma = &dev->dma; -	struct b43_dmaring *ring;  	int err;  	u64 dmamask;  	enum b43_dmatype type;  	dmamask = supported_dma_mask(dev); -	switch (dmamask) { -	default: -		B43_WARN_ON(1); -	case DMA_30BIT_MASK: -		type = B43_DMA_30BIT; -		break; -	case DMA_32BIT_MASK: -		type = B43_DMA_32BIT; -		break; -	case DMA_64BIT_MASK: -		type = B43_DMA_64BIT; -		break; -	} -	err = ssb_dma_set_mask(dev->dev, dmamask); -	if (err) { -		b43err(dev->wl, "The machine/kernel does not support " -		       "the required DMA mask (0x%08X%08X)\n", -		       (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32), -		       (unsigned int)(dmamask & 0x00000000FFFFFFFFULL)); -		return -EOPNOTSUPP; -	} +	type = dma_mask_to_engine_type(dmamask); +	err = b43_dma_set_mask(dev, dmamask); +	if (err) +		return err;  	err = -ENOMEM;  	/* setup TX DMA channels. */ -	ring = b43_setup_dmaring(dev, 0, 1, type); -	if (!ring) +	dma->tx_ring_AC_BK = b43_setup_dmaring(dev, 0, 1, type); +	if (!dma->tx_ring_AC_BK)  		goto out; -	dma->tx_ring0 = ring; -	ring = b43_setup_dmaring(dev, 1, 1, type); -	if (!ring) -		goto err_destroy_tx0; -	dma->tx_ring1 = ring; +	dma->tx_ring_AC_BE = b43_setup_dmaring(dev, 1, 1, type); +	if (!dma->tx_ring_AC_BE) +		goto err_destroy_bk; -	ring = b43_setup_dmaring(dev, 2, 1, type); -	if (!ring) -		goto err_destroy_tx1; -	dma->tx_ring2 = ring; +	dma->tx_ring_AC_VI = b43_setup_dmaring(dev, 2, 1, type); +	if (!dma->tx_ring_AC_VI) +		goto err_destroy_be; -	ring = b43_setup_dmaring(dev, 3, 1, type); -	if (!ring) -		goto err_destroy_tx2; -	dma->tx_ring3 = ring; +	dma->tx_ring_AC_VO = b43_setup_dmaring(dev, 3, 1, type); +	if (!dma->tx_ring_AC_VO) +		goto err_destroy_vi; -	ring = b43_setup_dmaring(dev, 4, 1, type); -	if (!ring) -		goto err_destroy_tx3; -	dma->tx_ring4 = ring; +	dma->tx_ring_mcast = b43_setup_dmaring(dev, 4, 1, type); +	if (!dma->tx_ring_mcast) +		goto err_destroy_vo; -	ring = b43_setup_dmaring(dev, 5, 1, type); -	if (!ring) -		goto err_destroy_tx4; -	dma->tx_ring5 = ring; +	/* setup RX DMA channel. */ +	dma->rx_ring = b43_setup_dmaring(dev, 0, 0, type); +	if (!dma->rx_ring) +		goto err_destroy_mcast; -	/* setup RX DMA channels. */ -	ring = b43_setup_dmaring(dev, 0, 0, type); -	if (!ring) -		goto err_destroy_tx5; -	dma->rx_ring0 = ring; - -	if (dev->dev->id.revision < 5) { -		ring = b43_setup_dmaring(dev, 3, 0, type); -		if (!ring) -			goto err_destroy_rx0; -		dma->rx_ring3 = ring; -	} +	/* No support for the TX status DMA ring. */ +	B43_WARN_ON(dev->dev->id.revision < 5);  	b43dbg(dev->wl, "%u-bit DMA initialized\n",  	       (unsigned int)type);  	err = 0; -      out: +out:  	return err; -      err_destroy_rx0: -	b43_destroy_dmaring(dma->rx_ring0); -	dma->rx_ring0 = NULL; -      err_destroy_tx5: -	b43_destroy_dmaring(dma->tx_ring5); -	dma->tx_ring5 = NULL; -      err_destroy_tx4: -	b43_destroy_dmaring(dma->tx_ring4); -	dma->tx_ring4 = NULL; -      err_destroy_tx3: -	b43_destroy_dmaring(dma->tx_ring3); -	dma->tx_ring3 = NULL; -      err_destroy_tx2: -	b43_destroy_dmaring(dma->tx_ring2); -	dma->tx_ring2 = NULL; -      err_destroy_tx1: -	b43_destroy_dmaring(dma->tx_ring1); -	dma->tx_ring1 = NULL; -      err_destroy_tx0: -	b43_destroy_dmaring(dma->tx_ring0); -	dma->tx_ring0 = NULL; -	goto out; +err_destroy_mcast: +	destroy_ring(dma, tx_ring_mcast); +err_destroy_vo: +	destroy_ring(dma, tx_ring_AC_VO); +err_destroy_vi: +	destroy_ring(dma, tx_ring_AC_VI); +err_destroy_be: +	destroy_ring(dma, tx_ring_AC_BE); +err_destroy_bk: +	destroy_ring(dma, tx_ring_AC_BK); +	return err;  }  /* Generate a cookie for the TX header. */  static u16 generate_cookie(struct b43_dmaring *ring, int slot)  { -	u16 cookie = 0x1000; +	u16 cookie;  	/* Use the upper 4 bits of the cookie as  	 * DMA controller ID and store the slot number @@ -1088,30 +1091,9 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)  	 * It can also not be 0xFFFF because that is special  	 * for multicast frames.  	 */ -	switch (ring->index) { -	case 0: -		cookie = 0x1000; -		break; -	case 1: -		cookie = 0x2000; -		break; -	case 2: -		cookie = 0x3000; -		break; -	case 3: -		cookie = 0x4000; -		break; -	case 4: -		cookie = 0x5000; -		break; -	case 5: -		cookie = 0x6000; -		break; -	default: -		B43_WARN_ON(1); -	} +	cookie = (((u16)ring->index + 1) << 12);  	B43_WARN_ON(slot & ~0x0FFF); -	cookie |= (u16) slot; +	cookie |= (u16)slot;  	return cookie;  } @@ -1125,22 +1107,19 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)  	switch (cookie & 0xF000) {  	case 0x1000: -		ring = dma->tx_ring0; +		ring = dma->tx_ring_AC_BK;  		break;  	case 0x2000: -		ring = dma->tx_ring1; +		ring = dma->tx_ring_AC_BE;  		break;  	case 0x3000: -		ring = dma->tx_ring2; +		ring = dma->tx_ring_AC_VI;  		break;  	case 0x4000: -		ring = dma->tx_ring3; +		ring = dma->tx_ring_AC_VO;  		break;  	case 0x5000: -		ring = dma->tx_ring4; -		break; -	case 0x6000: -		ring = dma->tx_ring5; +		ring = dma->tx_ring_mcast;  		break;  	default:  		B43_WARN_ON(1); @@ -1152,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)  }  static int dma_tx_fragment(struct b43_dmaring *ring, -			   struct sk_buff *skb, -			   struct ieee80211_tx_control *ctl) +			   struct sk_buff *skb)  {  	const struct b43_dma_ops *ops = ring->ops; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	u8 *header;  	int slot, old_top_slot, old_used_slots;  	int err; @@ -1167,7 +1146,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  	size_t hdrsize = b43_txhdr_size(ring->dev);  #define SLOTS_PER_PACKET  2 -	B43_WARN_ON(skb_shinfo(skb)->nr_frags);  	old_top_slot = ring->current_slot;  	old_used_slots = ring->used_slots; @@ -1180,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  	header = &(ring->txhdr_cache[slot * hdrsize]);  	cookie = generate_cookie(ring, slot);  	err = b43_generate_txhdr(ring->dev, header, -				 skb->data, skb->len, ctl, cookie); +				 skb->data, skb->len, info, cookie);  	if (unlikely(err)) {  		ring->current_slot = old_top_slot;  		ring->used_slots = old_used_slots; @@ -1189,7 +1167,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,  					   hdrsize, 1); -	if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) { +	if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) {  		ring->current_slot = old_top_slot;  		ring->used_slots = old_used_slots;  		return -EIO; @@ -1202,13 +1180,12 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  	desc = ops->idx2desc(ring, slot, &meta);  	memset(meta, 0, sizeof(*meta)); -	memcpy(&meta->txstat.control, ctl, sizeof(*ctl));  	meta->skb = skb;  	meta->is_last_fragment = 1;  	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);  	/* create a bounce buffer in zone_dma on mapping failure. */ -	if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { +	if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {  		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);  		if (!bounce_skb) {  			ring->current_slot = old_top_slot; @@ -1222,7 +1199,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  		skb = bounce_skb;  		meta->skb = skb;  		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); -		if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { +		if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {  			ring->current_slot = old_top_slot;  			ring->used_slots = old_used_slots;  			err = -EIO; @@ -1232,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,  	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); -	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { +	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {  		/* Tell the firmware about the cookie of the last  		 * mcast frame, so it can clear the more-data bit in it. */  		b43_shm_write16(ring->dev, B43_SHM_SHARED, @@ -1272,29 +1249,56 @@ static inline int should_inject_overflow(struct b43_dmaring *ring)  	return 0;  } -int b43_dma_tx(struct b43_wldev *dev, -	       struct sk_buff *skb, struct ieee80211_tx_control *ctl) +/* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ +static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, +						    u8 queue_prio) +{ +	struct b43_dmaring *ring; + +	if (b43_modparam_qos) { +		/* 0 = highest priority */ +		switch (queue_prio) { +		default: +			B43_WARN_ON(1); +			/* fallthrough */ +		case 0: +			ring = dev->dma.tx_ring_AC_VO; +			break; +		case 1: +			ring = dev->dma.tx_ring_AC_VI; +			break; +		case 2: +			ring = dev->dma.tx_ring_AC_BE; +			break; +		case 3: +			ring = dev->dma.tx_ring_AC_BK; +			break; +		} +	} else +		ring = dev->dma.tx_ring_AC_BE; + +	return ring; +} + +int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)  {  	struct b43_dmaring *ring;  	struct ieee80211_hdr *hdr;  	int err = 0;  	unsigned long flags; - -	if (unlikely(skb->len < 2 + 2 + 6)) { -		/* Too short, this can't be a valid frame. */ -		return -EINVAL; -	} +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	hdr = (struct ieee80211_hdr *)skb->data; -	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { +	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {  		/* The multicast ring will be sent after the DTIM */ -		ring = dev->dma.tx_ring4; +		ring = dev->dma.tx_ring_mcast;  		/* Set the more-data bit. Ucode will clear it on  		 * the last frame for us. */  		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);  	} else {  		/* Decide by priority where to put this frame. */ -		ring = priority_to_txring(dev, ctl->queue); +		ring = select_ring_by_priority( +			dev, skb_get_queue_mapping(skb));  	}  	spin_lock_irqsave(&ring->lock, flags); @@ -1309,7 +1313,12 @@ int b43_dma_tx(struct b43_wldev *dev,  	 * That would be a mac80211 bug. */  	B43_WARN_ON(ring->stopped); -	err = dma_tx_fragment(ring, skb, ctl); +	/* Assign the queue number to the ring (if not already done before) +	 * so TX status handling can use it. The queue to ring mapping is +	 * static, so we don't need to store it per frame. */ +	ring->queue_prio = skb_get_queue_mapping(skb); + +	err = dma_tx_fragment(ring, skb);  	if (unlikely(err == -ENOKEY)) {  		/* Drop this packet, as we don't have the encryption key  		 * anymore and must not transmit it unencrypted. */ @@ -1325,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev,  	if ((free_slots(ring) < SLOTS_PER_PACKET) ||  	    should_inject_overflow(ring)) {  		/* This TX ring is full. */ -		ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); +		ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));  		ring->stopped = 1;  		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {  			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1337,6 +1346,7 @@ out_unlock:  	return err;  } +/* Called with IRQs disabled. */  void b43_dma_handle_txstatus(struct b43_wldev *dev,  			     const struct b43_txstatus *status)  { @@ -1345,12 +1355,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	struct b43_dmadesc_generic *desc;  	struct b43_dmadesc_meta *meta;  	int slot; +	bool frame_succeed;  	ring = parse_cookie(dev, status->cookie, &slot);  	if (unlikely(!ring))  		return; -	B43_WARN_ON(!irqs_disabled()); -	spin_lock(&ring->lock); + +	spin_lock(&ring->lock); /* IRQs are already disabled. */  	B43_WARN_ON(!ring->tx);  	ops = ring->ops; @@ -1366,25 +1377,28 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  					 b43_txhdr_size(dev), 1);  		if (meta->is_last_fragment) { -			B43_WARN_ON(!meta->skb); -			/* Call back to inform the ieee80211 subsystem about the -			 * status of the transmission. -			 * Some fields of txstat are already filled in dma_tx(). +			struct ieee80211_tx_info *info; + +			BUG_ON(!meta->skb); + +			info = IEEE80211_SKB_CB(meta->skb); + +			memset(&info->status, 0, sizeof(info->status)); + +			/* +			 * Call back to inform the ieee80211 subsystem about +			 * the status of the transmission.  			 */ -			if (status->acked) { -				meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; -			} else { -				if (!(meta->txstat.control.flags -				      & IEEE80211_TXCTL_NO_ACK)) -					meta->txstat.excessive_retries = 1; -			} -			if (status->frame_count == 0) { -				/* The frame was not transmitted at all. */ -				meta->txstat.retry_count = 0; -			} else -				meta->txstat.retry_count = status->frame_count - 1; -			ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, -						    &(meta->txstat)); +			frame_succeed = b43_fill_txstatus_report(info, status); +#ifdef CONFIG_B43_DEBUG +			if (frame_succeed) +				ring->nr_succeed_tx_packets++; +			else +				ring->nr_failed_tx_packets++; +			ring->nr_total_packet_tries += status->frame_count; +#endif /* DEBUG */ +			ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); +  			/* skb is freed by ieee80211_tx_status_irqsafe() */  			meta->skb = NULL;  		} else { @@ -1404,7 +1418,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,  	dev->stats.last_tx = jiffies;  	if (ring->stopped) {  		B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); -		ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); +		ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);  		ring->stopped = 0;  		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {  			b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); @@ -1419,18 +1433,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,  {  	const int nr_queues = dev->wl->hw->queues;  	struct b43_dmaring *ring; -	struct ieee80211_tx_queue_stats_data *data;  	unsigned long flags;  	int i;  	for (i = 0; i < nr_queues; i++) { -		data = &(stats->data[i]); -		ring = priority_to_txring(dev, i); +		ring = select_ring_by_priority(dev, i);  		spin_lock_irqsave(&ring->lock, flags); -		data->len = ring->used_slots / SLOTS_PER_PACKET; -		data->limit = ring->nr_slots / SLOTS_PER_PACKET; -		data->count = ring->nr_tx_packets; +		stats[i].len = ring->used_slots / SLOTS_PER_PACKET; +		stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; +		stats[i].count = ring->nr_tx_packets;  		spin_unlock_irqrestore(&ring->lock, flags);  	}  } @@ -1451,25 +1463,6 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)  	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);  	skb = meta->skb; -	if (ring->index == 3) { -		/* We received an xmit status. */ -		struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data; -		int i = 0; - -		while (hw->cookie == 0) { -			if (i > 100) -				break; -			i++; -			udelay(2); -			barrier(); -		} -		b43_handle_hwtxstatus(ring->dev, hw); -		/* recycle the descriptor buffer. */ -		sync_descbuffer_for_device(ring, meta->dmaaddr, -					   ring->rx_buffersize); - -		return; -	}  	rxhdr = (struct b43_rxhdr_fw4 *)skb->data;  	len = le16_to_cpu(rxhdr->frame_len);  	if (len == 0) { @@ -1526,7 +1519,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)  	skb_pull(skb, ring->frameoffset);  	b43_rx(ring->dev, skb, rxhdr); -      drop: +drop:  	return;  } @@ -1572,21 +1565,55 @@ static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)  void b43_dma_tx_suspend(struct b43_wldev *dev)  {  	b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring0); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring1); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring2); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring3); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring4); -	b43_dma_tx_suspend_ring(dev->dma.tx_ring5); +	b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK); +	b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE); +	b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI); +	b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO); +	b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast);  }  void b43_dma_tx_resume(struct b43_wldev *dev)  { -	b43_dma_tx_resume_ring(dev->dma.tx_ring5); -	b43_dma_tx_resume_ring(dev->dma.tx_ring4); -	b43_dma_tx_resume_ring(dev->dma.tx_ring3); -	b43_dma_tx_resume_ring(dev->dma.tx_ring2); -	b43_dma_tx_resume_ring(dev->dma.tx_ring1); -	b43_dma_tx_resume_ring(dev->dma.tx_ring0); +	b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast); +	b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO); +	b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI); +	b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE); +	b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK);  	b43_power_saving_ctl_bits(dev, 0);  } + +#ifdef CONFIG_B43_PIO +static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type, +			   u16 mmio_base, bool enable) +{ +	u32 ctl; + +	if (type == B43_DMA_64BIT) { +		ctl = b43_read32(dev, mmio_base + B43_DMA64_RXCTL); +		ctl &= ~B43_DMA64_RXDIRECTFIFO; +		if (enable) +			ctl |= B43_DMA64_RXDIRECTFIFO; +		b43_write32(dev, mmio_base + B43_DMA64_RXCTL, ctl); +	} else { +		ctl = b43_read32(dev, mmio_base + B43_DMA32_RXCTL); +		ctl &= ~B43_DMA32_RXDIRECTFIFO; +		if (enable) +			ctl |= B43_DMA32_RXDIRECTFIFO; +		b43_write32(dev, mmio_base + B43_DMA32_RXCTL, ctl); +	} +} + +/* Enable/Disable Direct FIFO Receive Mode (PIO) on a RX engine. + * This is called from PIO code, so DMA structures are not available. */ +void b43_dma_direct_fifo_rx(struct b43_wldev *dev, +			    unsigned int engine_index, bool enable) +{ +	enum b43_dmatype type; +	u16 mmio_base; + +	type = dma_mask_to_engine_type(supported_dma_mask(dev)); + +	mmio_base = b43_dmacontroller_base(type, engine_index); +	direct_fifo_rx(dev, type, mmio_base, enable); +} +#endif /* CONFIG_B43_PIO */ diff --git a/package/b43/src/dma.h b/package/b43/src/dma.h index c0d6b69e6..d1eb5c084 100644 --- a/package/b43/src/dma.h +++ b/package/b43/src/dma.h @@ -181,7 +181,6 @@ struct b43_dmadesc_meta {  	dma_addr_t dmaaddr;  	/* ieee80211 TX status. Only used once per 802.11 frag. */  	bool is_last_fragment; -	struct ieee80211_tx_status txstat;  };  struct b43_dmaring; @@ -245,6 +244,9 @@ struct b43_dmaring {  	enum b43_dmatype type;  	/* Boolean. Is this ring stopped at ieee80211 level? */  	bool stopped; +	/* The QOS priority assigned to this ring. Only used for TX rings. +	 * This is the mac80211 "queue" value. */ +	u8 queue_prio;  	/* Lock, only used for TX. */  	spinlock_t lock;  	struct b43_wldev *dev; @@ -253,7 +255,13 @@ struct b43_dmaring {  	int max_used_slots;  	/* Last time we injected a ring overflow. */  	unsigned long last_injected_overflow; -#endif				/* CONFIG_B43_DEBUG */ +	/* Statistics: Number of successfully transmitted packets */ +	u64 nr_succeed_tx_packets; +	/* Statistics: Number of failed TX packets */ +	u64 nr_failed_tx_packets; +	/* Statistics: Total number of TX plus all retries. */ +	u64 nr_total_packet_tries; +#endif /* CONFIG_B43_DEBUG */  };  static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) @@ -276,10 +284,13 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,  			  struct ieee80211_tx_queue_stats *stats);  int b43_dma_tx(struct b43_wldev *dev, -	       struct sk_buff *skb, struct ieee80211_tx_control *ctl); +	       struct sk_buff *skb);  void b43_dma_handle_txstatus(struct b43_wldev *dev,  			     const struct b43_txstatus *status);  void b43_dma_rx(struct b43_dmaring *ring); +void b43_dma_direct_fifo_rx(struct b43_wldev *dev, +			    unsigned int engine_index, bool enable); +  #endif /* B43_DMA_H_ */ diff --git a/package/b43/src/leds.c b/package/b43/src/leds.c index 4b590d8c6..36a9c42df 100644 --- a/package/b43/src/leds.c +++ b/package/b43/src/leds.c @@ -144,12 +144,12 @@ static void b43_map_led(struct b43_wldev *dev,  	case B43_LED_TRANSFER:  	case B43_LED_APTRANSFER:  		snprintf(name, sizeof(name), -			 "b43-%s:tx", wiphy_name(hw->wiphy)); +			 "b43-%s::tx", wiphy_name(hw->wiphy));  		b43_register_led(dev, &dev->led_tx, name,  				 ieee80211_get_tx_led_name(hw),  				 led_index, activelow);  		snprintf(name, sizeof(name), -			 "b43-%s:rx", wiphy_name(hw->wiphy)); +			 "b43-%s::rx", wiphy_name(hw->wiphy));  		b43_register_led(dev, &dev->led_rx, name,  				 ieee80211_get_rx_led_name(hw),  				 led_index, activelow); @@ -159,7 +159,7 @@ static void b43_map_led(struct b43_wldev *dev,  	case B43_LED_RADIO_B:  	case B43_LED_MODE_BG:  		snprintf(name, sizeof(name), -			 "b43-%s:radio", wiphy_name(hw->wiphy)); +			 "b43-%s::radio", wiphy_name(hw->wiphy));  		b43_register_led(dev, &dev->led_radio, name,  				 b43_rfkill_led_name(dev),  				 led_index, activelow); @@ -170,7 +170,7 @@ static void b43_map_led(struct b43_wldev *dev,  	case B43_LED_WEIRD:  	case B43_LED_ASSOC:  		snprintf(name, sizeof(name), -			 "b43-%s:assoc", wiphy_name(hw->wiphy)); +			 "b43-%s::assoc", wiphy_name(hw->wiphy));  		b43_register_led(dev, &dev->led_assoc, name,  				 ieee80211_get_assoc_led_name(hw),  				 led_index, activelow); diff --git a/package/b43/src/lo.c b/package/b43/src/lo.c index d890f366a..9c854d6aa 100644 --- a/package/b43/src/lo.c +++ b/package/b43/src/lo.c @@ -36,17 +36,28 @@  #include <linux/sched.h> -/* Define to 1 to always calibrate all possible LO control pairs. - * This is a workaround until we fix the partial LO calibration optimization. */ -#define B43_CALIB_ALL_LOCTLS	1 +static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo, +					       const struct b43_bbatt *bbatt, +					       const struct b43_rfatt *rfatt) +{ +	struct b43_lo_calib *c; + +	list_for_each_entry(c, &lo->calib_list, list) { +		if (!b43_compare_bbatt(&c->bbatt, bbatt)) +			continue; +		if (!b43_compare_rfatt(&c->rfatt, rfatt)) +			continue; +		return c; +	} +	return NULL; +}  /* Write the LocalOscillator Control (adjust) value-pair. */  static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)  {  	struct b43_phy *phy = &dev->phy;  	u16 value; -	u16 reg;  	if (B43_DEBUG) {  		if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { @@ -56,189 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)  			return;  		}  	} +	B43_WARN_ON(phy->type != B43_PHYTYPE_G);  	value = (u8) (control->q);  	value |= ((u8) (control->i)) << 8; - -	reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; -	b43_phy_write(dev, reg, value); -} - -static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, -				  const struct b43_bbatt *bbatt, -				  struct b43_wldev *dev) -{ -	int err = 0; - -	/* Check the attenuation values against the LO control array sizes. */ -	if (unlikely(rfatt->att >= B43_NR_RF)) { -		b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); -		err = -EINVAL; -	} -	if (unlikely(bbatt->att >= B43_NR_BB)) { -		b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); -		err = -EINVAL; -	} - -	return err; -} - -#if !B43_CALIB_ALL_LOCTLS -static -struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, -					    const struct b43_rfatt *rfatt, -					    const struct b43_bbatt *bbatt) -{ -	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control; - -	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) -		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */ -	return &(lo->no_padmix[bbatt->att][rfatt->att]); -} -#endif /* !B43_CALIB_ALL_LOCTLS */ - -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, -				   const struct b43_rfatt *rfatt, -				   const struct b43_bbatt *bbatt) -{ -	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control; - -	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) -		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */ -	if (rfatt->with_padmix) -		return &(lo->with_padmix[bbatt->att][rfatt->att]); -	return &(lo->no_padmix[bbatt->att][rfatt->att]); -} - -/* Call a function for every possible LO control value-pair. */ -static void b43_call_for_each_loctl(struct b43_wldev *dev, -				    void (*func) (struct b43_wldev *, -						  struct b43_loctl *)) -{ -	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *ctl = phy->lo_control; -	int i, j; - -	for (i = 0; i < B43_NR_BB; i++) { -		for (j = 0; j < B43_NR_RF; j++) -			func(dev, &(ctl->with_padmix[i][j])); -	} -	for (i = 0; i < B43_NR_BB; i++) { -		for (j = 0; j < B43_NR_RF; j++) -			func(dev, &(ctl->no_padmix[i][j])); -	} -} - -static u16 lo_b_r15_loop(struct b43_wldev *dev) -{ -	int i; -	u16 ret = 0; - -	for (i = 0; i < 10; i++) { -		b43_phy_write(dev, 0x0015, 0xAFA0); -		udelay(1); -		b43_phy_write(dev, 0x0015, 0xEFA0); -		udelay(10); -		b43_phy_write(dev, 0x0015, 0xFFA0); -		udelay(40); -		ret += b43_phy_read(dev, 0x002C); -	} - -	return ret; -} - -void b43_lo_b_measure(struct b43_wldev *dev) -{ -	struct b43_phy *phy = &dev->phy; -	u16 regstack[12] = { 0 }; -	u16 mls; -	u16 fval; -	int i, j; - -	regstack[0] = b43_phy_read(dev, 0x0015); -	regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; - -	if (phy->radio_ver == 0x2053) { -		regstack[2] = b43_phy_read(dev, 0x000A); -		regstack[3] = b43_phy_read(dev, 0x002A); -		regstack[4] = b43_phy_read(dev, 0x0035); -		regstack[5] = b43_phy_read(dev, 0x0003); -		regstack[6] = b43_phy_read(dev, 0x0001); -		regstack[7] = b43_phy_read(dev, 0x0030); - -		regstack[8] = b43_radio_read16(dev, 0x0043); -		regstack[9] = b43_radio_read16(dev, 0x007A); -		regstack[10] = b43_read16(dev, 0x03EC); -		regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; - -		b43_phy_write(dev, 0x0030, 0x00FF); -		b43_write16(dev, 0x03EC, 0x3F3F); -		b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); -		b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); -	} -	b43_phy_write(dev, 0x0015, 0xB000); -	b43_phy_write(dev, 0x002B, 0x0004); - -	if (phy->radio_ver == 0x2053) { -		b43_phy_write(dev, 0x002B, 0x0203); -		b43_phy_write(dev, 0x002A, 0x08A3); -	} - -	phy->minlowsig[0] = 0xFFFF; - -	for (i = 0; i < 4; i++) { -		b43_radio_write16(dev, 0x0052, regstack[1] | i); -		lo_b_r15_loop(dev); -	} -	for (i = 0; i < 10; i++) { -		b43_radio_write16(dev, 0x0052, regstack[1] | i); -		mls = lo_b_r15_loop(dev) / 10; -		if (mls < phy->minlowsig[0]) { -			phy->minlowsig[0] = mls; -			phy->minlowsigpos[0] = i; -		} -	} -	b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); - -	phy->minlowsig[1] = 0xFFFF; - -	for (i = -4; i < 5; i += 2) { -		for (j = -4; j < 5; j += 2) { -			if (j < 0) -				fval = (0x0100 * i) + j + 0x0100; -			else -				fval = (0x0100 * i) + j; -			b43_phy_write(dev, 0x002F, fval); -			mls = lo_b_r15_loop(dev) / 10; -			if (mls < phy->minlowsig[1]) { -				phy->minlowsig[1] = mls; -				phy->minlowsigpos[1] = fval; -			} -		} -	} -	phy->minlowsigpos[1] += 0x0101; - -	b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); -	if (phy->radio_ver == 0x2053) { -		b43_phy_write(dev, 0x000A, regstack[2]); -		b43_phy_write(dev, 0x002A, regstack[3]); -		b43_phy_write(dev, 0x0035, regstack[4]); -		b43_phy_write(dev, 0x0003, regstack[5]); -		b43_phy_write(dev, 0x0001, regstack[6]); -		b43_phy_write(dev, 0x0030, regstack[7]); - -		b43_radio_write16(dev, 0x0043, regstack[8]); -		b43_radio_write16(dev, 0x007A, regstack[9]); - -		b43_radio_write16(dev, 0x0052, -				  (b43_radio_read16(dev, 0x0052) & 0x000F) -				  | regstack[11]); - -		b43_write16(dev, 0x03EC, regstack[10]); -	} -	b43_phy_write(dev, 0x0015, regstack[0]); +	b43_phy_write(dev, B43_PHY_LO_CTL, value);  }  static u16 lo_measure_feedthrough(struct b43_wldev *dev, @@ -366,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)  		if (lb_gain > 10) {  			radio_pctl_reg = 0;  			pga = abs(10 - lb_gain) / 6; -			pga = limit_value(pga, 0, 15); +			pga = clamp_val(pga, 0, 15);  		} else {  			int cmp_val;  			int tmp; @@ -438,48 +271,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)  		b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)  				  & 0xFFF0);	/* TX bias == 0 */  	} +	lo->txctl_measured_time = jiffies;  }  static void lo_read_power_vector(struct b43_wldev *dev)  {  	struct b43_phy *phy = &dev->phy;  	struct b43_txpower_lo_control *lo = phy->lo_control; -	u16 i; +	int i;  	u64 tmp;  	u64 power_vector = 0; -	int rf_offset, bb_offset; -	struct b43_loctl *loctl;  	for (i = 0; i < 8; i += 2) {  		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); -		/* Clear the top byte. We get holes in the bitmap... */ -		tmp &= 0xFF;  		power_vector |= (tmp << (i * 8));  		/* Clear the vector on the device. */  		b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);  	} -  	if (power_vector)  		lo->power_vector = power_vector; -	power_vector = lo->power_vector; - -	for (i = 0; i < 64; i++) { -		if (power_vector & ((u64) 1ULL << i)) { -			/* Now figure out which b43_loctl corresponds -			 * to this bit. -			 */ -			rf_offset = i / lo->rfatt_list.len; -			bb_offset = i % lo->rfatt_list.len;	//FIXME? -			loctl = -			    b43_get_lo_g_ctl(dev, -					     &lo->rfatt_list.list[rf_offset], -					     &lo->bbatt_list.list[bb_offset]); -			/* And mark it as "used", as the device told us -			 * through the bitmap it is using it. -			 */ -			loctl->used = 1; -		} -	} +	lo->pwr_vec_read_time = jiffies;  }  /* 802.11/LO/GPHY/MeasuringGains */ @@ -510,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,  			phy->lna_lod_gain = 1;  			trsw_rx_gain -= 8;  		} -		trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); +		trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);  		phy->pga_gain = trsw_rx_gain / 3;  		if (phy->pga_gain >= 5) {  			phy->pga_gain -= 5; @@ -609,8 +420,6 @@ static void lo_measure_setup(struct b43_wldev *dev,  		b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);  		b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);  	} -	if (!lo->rebuild && b43_has_hardware_pctl(phy)) -		lo_read_power_vector(dev);  	if (phy->rev >= 2) {  		sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);  		sav->phy_analogoverval = @@ -691,8 +500,12 @@ static void lo_measure_setup(struct b43_wldev *dev,  	b43_radio_read16(dev, 0x51);	/* dummy read */  	if (phy->type == B43_PHYTYPE_G)  		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); -	if (lo->rebuild) + +	/* Re-measure the txctl values, if needed. */ +	if (time_before(lo->txctl_measured_time, +			jiffies - B43_LO_TXCTL_EXPIRE))  		lo_measure_txctl_values(dev); +  	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {  		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);  	} else { @@ -707,7 +520,6 @@ static void lo_measure_restore(struct b43_wldev *dev,  			       struct lo_g_saved_values *sav)  {  	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control;  	u16 tmp;  	if (phy->rev >= 2) { @@ -722,14 +534,6 @@ static void lo_measure_restore(struct b43_wldev *dev,  		tmp = (phy->pga_gain | 0xEFA0);  		b43_phy_write(dev, B43_PHY_PGACTL, tmp);  	} -	if (b43_has_hardware_pctl(phy)) { -		b43_gphy_dc_lt_init(dev); -	} else { -		if (lo->rebuild) -			b43_lo_g_adjust_to(dev, 3, 2, 0); -		else -			b43_lo_g_adjust(dev); -	}  	if (phy->type == B43_PHYTYPE_G) {  		if (phy->rev >= 3)  			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); @@ -793,7 +597,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,  				    struct b43_lo_g_statemachine *d)  {  	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control;  	struct b43_loctl test_loctl;  	struct b43_loctl orig_loctl;  	struct b43_loctl prev_loctl = { @@ -852,7 +655,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,  				found_lower = 1;  				d->lowest_feedth = feedth;  				if ((d->nr_measured < 2) && -				    (!has_loopback_gain(phy) || lo->rebuild)) +				    !has_loopback_gain(phy))  					break;  			}  		} @@ -874,7 +677,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,  					 int *max_rx_gain)  {  	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control;  	struct b43_lo_g_statemachine d;  	u16 feedth;  	int found_lower; @@ -883,18 +685,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,  	d.nr_measured = 0;  	d.state_val_multiplier = 1; -	if (has_loopback_gain(phy) && !lo->rebuild) +	if (has_loopback_gain(phy))  		d.state_val_multiplier = 3;  	memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); -	if (has_loopback_gain(phy) && lo->rebuild) +	if (has_loopback_gain(phy))  		max_repeat = 4;  	do {  		b43_lo_write(dev, &d.min_loctl);  		feedth = lo_measure_feedthrough(dev, phy->lna_gain,  						phy->pga_gain,  						phy->trsw_rx_gain); -		if (!lo->rebuild && feedth < 0x258) { +		if (feedth < 0x258) {  			if (feedth >= 0x12C)  				*max_rx_gain += 6;  			else @@ -944,278 +746,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,  	} while (++repeat_cnt < max_repeat);  } -#if B43_CALIB_ALL_LOCTLS -static const struct b43_rfatt b43_full_rfatt_list_items[] = { -	{ .att = 0, .with_padmix = 0, }, -	{ .att = 1, .with_padmix = 0, }, -	{ .att = 2, .with_padmix = 0, }, -	{ .att = 3, .with_padmix = 0, }, -	{ .att = 4, .with_padmix = 0, }, -	{ .att = 5, .with_padmix = 0, }, -	{ .att = 6, .with_padmix = 0, }, -	{ .att = 7, .with_padmix = 0, }, -	{ .att = 8, .with_padmix = 0, }, -	{ .att = 9, .with_padmix = 0, }, -	{ .att = 10, .with_padmix = 0, }, -	{ .att = 11, .with_padmix = 0, }, -	{ .att = 12, .with_padmix = 0, }, -	{ .att = 13, .with_padmix = 0, }, -	{ .att = 14, .with_padmix = 0, }, -	{ .att = 15, .with_padmix = 0, }, -	{ .att = 0, .with_padmix = 1, }, -	{ .att = 1, .with_padmix = 1, }, -	{ .att = 2, .with_padmix = 1, }, -	{ .att = 3, .with_padmix = 1, }, -	{ .att = 4, .with_padmix = 1, }, -	{ .att = 5, .with_padmix = 1, }, -	{ .att = 6, .with_padmix = 1, }, -	{ .att = 7, .with_padmix = 1, }, -	{ .att = 8, .with_padmix = 1, }, -	{ .att = 9, .with_padmix = 1, }, -	{ .att = 10, .with_padmix = 1, }, -	{ .att = 11, .with_padmix = 1, }, -	{ .att = 12, .with_padmix = 1, }, -	{ .att = 13, .with_padmix = 1, }, -	{ .att = 14, .with_padmix = 1, }, -	{ .att = 15, .with_padmix = 1, }, -}; -static const struct b43_rfatt_list b43_full_rfatt_list = { -	.list		= b43_full_rfatt_list_items, -	.len		= ARRAY_SIZE(b43_full_rfatt_list_items), -}; - -static const struct b43_bbatt b43_full_bbatt_list_items[] = { -	{ .att = 0, }, -	{ .att = 1, }, -	{ .att = 2, }, -	{ .att = 3, }, -	{ .att = 4, }, -	{ .att = 5, }, -	{ .att = 6, }, -	{ .att = 7, }, -	{ .att = 8, }, -	{ .att = 9, }, -	{ .att = 10, }, -	{ .att = 11, }, -}; -static const struct b43_bbatt_list b43_full_bbatt_list = { -	.list		= b43_full_bbatt_list_items, -	.len		= ARRAY_SIZE(b43_full_bbatt_list_items), -}; -#endif /* B43_CALIB_ALL_LOCTLS */ - -static void lo_measure(struct b43_wldev *dev) +static +struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, +					       const struct b43_bbatt *bbatt, +					       const struct b43_rfatt *rfatt)  {  	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control;  	struct b43_loctl loctl = {  		.i = 0,  		.q = 0,  	}; -	struct b43_loctl *ploctl;  	int max_rx_gain; -	int rfidx, bbidx; -	const struct b43_bbatt_list *bbatt_list; -	const struct b43_rfatt_list *rfatt_list; - +	struct b43_lo_calib *cal; +	struct lo_g_saved_values uninitialized_var(saved_regs);  	/* Values from the "TXCTL Register and Value Table" */  	u16 txctl_reg;  	u16 txctl_value;  	u16 pad_mix_gain; -	bbatt_list = &lo->bbatt_list; -	rfatt_list = &lo->rfatt_list; -#if B43_CALIB_ALL_LOCTLS -	bbatt_list = &b43_full_bbatt_list; -	rfatt_list = &b43_full_rfatt_list; -#endif +	saved_regs.old_channel = phy->channel; +	b43_mac_suspend(dev); +	lo_measure_setup(dev, &saved_regs);  	txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); -	for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { - -		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) -					      & 0xFFF0) | -				  rfatt_list->list[rfidx].att); -		b43_radio_write16(dev, txctl_reg, -				  (b43_radio_read16(dev, txctl_reg) -				   & ~txctl_value) -				  | (rfatt_list->list[rfidx].with_padmix ? -				     txctl_value : 0)); - -		for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { -			if (lo->rebuild) { -#if B43_CALIB_ALL_LOCTLS -				ploctl = b43_get_lo_g_ctl(dev, -							  &rfatt_list->list[rfidx], -							  &bbatt_list->list[bbidx]); -#else -				ploctl = b43_get_lo_g_ctl_nopadmix(dev, -								   &rfatt_list-> -								   list[rfidx], -								   &bbatt_list-> -								   list[bbidx]); -#endif -			} else { -				ploctl = b43_get_lo_g_ctl(dev, -							  &rfatt_list->list[rfidx], -							  &bbatt_list->list[bbidx]); -				if (!ploctl->used) -					continue; -			} -			memcpy(&loctl, ploctl, sizeof(loctl)); -			loctl.i = 0; -			loctl.q = 0; - -			max_rx_gain = rfatt_list->list[rfidx].att * 2; -			max_rx_gain += bbatt_list->list[bbidx].att / 2; -			if (rfatt_list->list[rfidx].with_padmix) -				max_rx_gain -= pad_mix_gain; -			if (has_loopback_gain(phy)) -				max_rx_gain += phy->max_lb_gain; -			lo_measure_gain_values(dev, max_rx_gain, -					       has_loopback_gain(phy)); - -			b43_phy_set_baseband_attenuation(dev, -							 bbatt_list->list[bbidx].att); -			lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); -			if (phy->type == B43_PHYTYPE_B) { -				loctl.i++; -				loctl.q++; -			} -			b43_loctl_set_calibrated(&loctl, 1); -			memcpy(ploctl, &loctl, sizeof(loctl)); -		} -	} -} - -#if B43_DEBUG -static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) -{ -	const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); -	int i = control->i; -	int q = control->q; +	b43_radio_write16(dev, 0x43, +			  (b43_radio_read16(dev, 0x43) & 0xFFF0) +			  | rfatt->att); +	b43_radio_write16(dev, txctl_reg, +			  (b43_radio_read16(dev, txctl_reg) & ~txctl_value) +			  | (rfatt->with_padmix) ? txctl_value : 0); -	if (b43_loctl_is_calibrated(control)) { -		if ((abs(i) > 16) || (abs(q) > 16)) -			goto error; -	} else { -		if (control->used) -			goto error; -		if (dev->phy.lo_control->rebuild) { -			control->i = 0; -			control->q = 0; -			if ((i != B43_LOCTL_POISON) || -			    (q != B43_LOCTL_POISON)) -				goto error; -		} +	max_rx_gain = rfatt->att * 2; +	max_rx_gain += bbatt->att / 2; +	if (rfatt->with_padmix) +		max_rx_gain -= pad_mix_gain; +	if (has_loopback_gain(phy)) +		max_rx_gain += phy->max_lb_gain; +	lo_measure_gain_values(dev, max_rx_gain, +			       has_loopback_gain(phy)); + +	b43_phy_set_baseband_attenuation(dev, bbatt->att); +	lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + +	lo_measure_restore(dev, &saved_regs); +	b43_mac_enable(dev); + +	if (b43_debug(dev, B43_DBG_LO)) { +		b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " +		       "=> I=%d Q=%d\n", +		       bbatt->att, rfatt->att, rfatt->with_padmix, +		       loctl.i, loctl.q);  	} -	if (is_initializing && control->used) -		goto error; - -	return; -error: -	b43err(dev->wl, "LO control pair validation failed " -	       "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", -	       i, q, control->used, -	       b43_loctl_is_calibrated(control), -	       is_initializing); -} -static void validate_all_loctls(struct b43_wldev *dev) -{ -	b43_call_for_each_loctl(dev, do_validate_loctl); -} - -static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) -{ -	if (dev->phy.lo_control->rebuild || -	    control->used) { -		b43_loctl_set_calibrated(control, 0); -		control->i = B43_LOCTL_POISON; -		control->q = B43_LOCTL_POISON; +	cal = kmalloc(sizeof(*cal), GFP_KERNEL); +	if (!cal) { +		b43warn(dev->wl, "LO calib: out of memory\n"); +		return NULL;  	} +	memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); +	memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); +	memcpy(&cal->ctl, &loctl, sizeof(loctl)); +	cal->calib_time = jiffies; +	INIT_LIST_HEAD(&cal->list); + +	return cal;  } -static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +/* Get a calibrated LO setting for the given attenuation values. + * Might return a NULL pointer under OOM! */ +static +struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, +						const struct b43_bbatt *bbatt, +						const struct b43_rfatt *rfatt)  { -	b43_call_for_each_loctl(dev, do_reset_calib); +	struct b43_txpower_lo_control *lo = dev->phy.lo_control; +	struct b43_lo_calib *c; + +	c = b43_find_lo_calib(lo, bbatt, rfatt); +	if (c) +		return c; +	/* Not in the list of calibrated LO settings. +	 * Calibrate it now. */ +	c = b43_calibrate_lo_setting(dev, bbatt, rfatt); +	if (!c) +		return NULL; +	list_add(&c->list, &lo->calib_list); + +	return c;  } -#else /* B43_DEBUG */ -static inline void validate_all_loctls(struct b43_wldev *dev) { } -static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } -#endif /* B43_DEBUG */ - -void b43_lo_g_measure(struct b43_wldev *dev) +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)  {  	struct b43_phy *phy = &dev->phy; -	struct lo_g_saved_values uninitialized_var(sav); - -	B43_WARN_ON((phy->type != B43_PHYTYPE_B) && -		    (phy->type != B43_PHYTYPE_G)); - -	sav.old_channel = phy->channel; -	lo_measure_setup(dev, &sav); -	reset_all_loctl_calibration_states(dev); -	lo_measure(dev); -	lo_measure_restore(dev, &sav); - -	validate_all_loctls(dev); +	struct b43_txpower_lo_control *lo = phy->lo_control; +	int i; +	int rf_offset, bb_offset; +	const struct b43_rfatt *rfatt; +	const struct b43_bbatt *bbatt; +	u64 power_vector; +	bool table_changed = 0; -	phy->lo_control->lo_measured = 1; -	phy->lo_control->rebuild = 0; -} +	BUILD_BUG_ON(B43_DC_LT_SIZE != 32); +	B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); -#if B43_DEBUG -static void validate_loctl_calibration(struct b43_wldev *dev, -				       struct b43_loctl *loctl, -				       struct b43_rfatt *rfatt, -				       struct b43_bbatt *bbatt) -{ -	if (b43_loctl_is_calibrated(loctl)) -		return; -	if (!dev->phy.lo_control->lo_measured) { -		/* On init we set the attenuation values before we -		 * calibrated the LO. I guess that's OK. */ -		return; +	power_vector = lo->power_vector; +	if (!update_all && !power_vector) +		return; /* Nothing to do. */ + +	/* Suspend the MAC now to avoid continuous suspend/enable +	 * cycles in the loop. */ +	b43_mac_suspend(dev); + +	for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { +		struct b43_lo_calib *cal; +		int idx; +		u16 val; + +		if (!update_all && !(power_vector & (((u64)1ULL) << i))) +			continue; +		/* Update the table entry for this power_vector bit. +		 * The table rows are RFatt entries and columns are BBatt. */ +		bb_offset = i / lo->rfatt_list.len; +		rf_offset = i % lo->rfatt_list.len; +		bbatt = &(lo->bbatt_list.list[bb_offset]); +		rfatt = &(lo->rfatt_list.list[rf_offset]); + +		cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); +		if (!cal) { +			b43warn(dev->wl, "LO: Could not " +				"calibrate DC table entry\n"); +			continue; +		} +		/*FIXME: Is Q really in the low nibble? */ +		val = (u8)(cal->ctl.q); +		val |= ((u8)(cal->ctl.i)) << 4; +		kfree(cal); + +		/* Get the index into the hardware DC LT. */ +		idx = i / 2; +		/* Change the table in memory. */ +		if (i % 2) { +			/* Change the high byte. */ +			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) +					 | ((val & 0x00FF) << 8); +		} else { +			/* Change the low byte. */ +			lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) +					 | (val & 0x00FF); +		} +		table_changed = 1;  	} -	b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " -	       "control pair: rfatt=%u,%spadmix bbatt=%u\n", -	       rfatt->att, -	       (rfatt->with_padmix) ? "" : "no-", -	       bbatt->att); -} -#else -static inline void validate_loctl_calibration(struct b43_wldev *dev, -					      struct b43_loctl *loctl, -					      struct b43_rfatt *rfatt, -					      struct b43_bbatt *bbatt) -{ +	if (table_changed) { +		/* The table changed in memory. Update the hardware table. */ +		for (i = 0; i < B43_DC_LT_SIZE; i++) +			b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); +	} +	b43_mac_enable(dev);  } -#endif -static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, -					     u8 tx_control) +/* Fixup the RF attenuation value for the case where we are + * using the PAD mixer. */ +static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)  { -	if (tx_control & B43_TXCTL_TXMIX) { -		if (rf->att < 5) -			rf->att = 4; -	} +	if (!rf->with_padmix) +		return; +	if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) +		rf->att = 4;  }  void b43_lo_g_adjust(struct b43_wldev *dev)  {  	struct b43_phy *phy = &dev->phy; +	struct b43_lo_calib *cal;  	struct b43_rfatt rf; -	struct b43_loctl *loctl;  	memcpy(&rf, &phy->rfatt, sizeof(rf)); -	fixup_rfatt_for_txcontrol(&rf, phy->tx_control); +	b43_lo_fixup_rfatt(&rf); -	loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); -	validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); -	b43_lo_write(dev, loctl); +	cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); +	if (!cal) +		return; +	b43_lo_write(dev, &cal->ctl);  }  void b43_lo_g_adjust_to(struct b43_wldev *dev, @@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,  {  	struct b43_rfatt rf;  	struct b43_bbatt bb; -	struct b43_loctl *loctl; +	struct b43_lo_calib *cal;  	memset(&rf, 0, sizeof(rf));  	memset(&bb, 0, sizeof(bb));  	rf.att = rfatt;  	bb.att = bbatt; -	fixup_rfatt_for_txcontrol(&rf, tx_control); -	loctl = b43_get_lo_g_ctl(dev, &rf, &bb); -	validate_loctl_calibration(dev, loctl, &rf, &bb); -	b43_lo_write(dev, loctl); +	b43_lo_fixup_rfatt(&rf); +	cal = b43_get_calib_lo_settings(dev, &bb, &rf); +	if (!cal) +		return; +	b43_lo_write(dev, &cal->ctl);  } -static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +/* Periodic LO maintanance work */ +void b43_lo_g_maintanance_work(struct b43_wldev *dev)  { -	control->used = 0; +	struct b43_phy *phy = &dev->phy; +	struct b43_txpower_lo_control *lo = phy->lo_control; +	unsigned long now; +	unsigned long expire; +	struct b43_lo_calib *cal, *tmp; +	bool current_item_expired = 0; +	bool hwpctl; + +	if (!lo) +		return; +	now = jiffies; +	hwpctl = b43_has_hardware_pctl(phy); + +	if (hwpctl) { +		/* Read the power vector and update it, if needed. */ +		expire = now - B43_LO_PWRVEC_EXPIRE; +		if (time_before(lo->pwr_vec_read_time, expire)) { +			lo_read_power_vector(dev); +			b43_gphy_dc_lt_init(dev, 0); +		} +		//FIXME Recalc the whole DC table from time to time? +	} + +	if (hwpctl) +		return; +	/* Search for expired LO settings. Remove them. +	 * Recalibrate the current setting, if expired. */ +	expire = now - B43_LO_CALIB_EXPIRE; +	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { +		if (!time_before(cal->calib_time, expire)) +			continue; +		/* This item expired. */ +		if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && +		    b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { +			B43_WARN_ON(current_item_expired); +			current_item_expired = 1; +		} +		if (b43_debug(dev, B43_DBG_LO)) { +			b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " +			       "I=%d, Q=%d expired\n", +			       cal->bbatt.att, cal->rfatt.att, +			       cal->rfatt.with_padmix, +			       cal->ctl.i, cal->ctl.q); +		} +		list_del(&cal->list); +		kfree(cal); +	} +	if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { +		/* Recalibrate currently used LO setting. */ +		if (b43_debug(dev, B43_DBG_LO)) +			b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); +		cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); +		if (cal) { +			list_add(&cal->list, &lo->calib_list); +			b43_lo_write(dev, &cal->ctl); +		} else +			b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); +	}  } -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +void b43_lo_g_cleanup(struct b43_wldev *dev)  { -	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control; +	struct b43_txpower_lo_control *lo = dev->phy.lo_control; +	struct b43_lo_calib *cal, *tmp; -	b43_call_for_each_loctl(dev, do_mark_unused); -	lo->rebuild = 1; +	if (!lo) +		return; +	list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { +		list_del(&cal->list); +		kfree(cal); +	}  } -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +/* LO Initialization */ +void b43_lo_g_init(struct b43_wldev *dev)  {  	struct b43_phy *phy = &dev->phy; -	struct b43_rfatt rf; -	memcpy(&rf, &phy->rfatt, sizeof(rf)); -	fixup_rfatt_for_txcontrol(&rf, phy->tx_control); - -	b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; +	if (b43_has_hardware_pctl(phy)) { +		lo_read_power_vector(dev); +		b43_gphy_dc_lt_init(dev, 1); +	}  } diff --git a/package/b43/src/lo.h b/package/b43/src/lo.h index 455615d1f..1da321cab 100644 --- a/package/b43/src/lo.h +++ b/package/b43/src/lo.h @@ -10,82 +10,63 @@ struct b43_loctl {  	/* Control values. */  	s8 i;  	s8 q; -	/* "Used by hardware" flag. */ -	bool used; -#ifdef CONFIG_B43_DEBUG -	/* Is this lo-control-array entry calibrated? */ -	bool calibrated; -#endif  }; -  /* Debugging: Poison value for i and q values. */  #define B43_LOCTL_POISON	111 -/* loctl->calibrated debugging mechanism */ -#ifdef CONFIG_B43_DEBUG -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, -					    bool calibrated) -{ -	loctl->calibrated = calibrated; -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ -	return loctl->calibrated; -} -#else -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, -					    bool calibrated) -{ -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ -	return 1; -} -#endif - -/* TX Power LO Control Array. - * Value-pairs to adjust the LocalOscillator are stored - * in this structure. - * There are two different set of values. One for "Flag is Set" - * and one for "Flag is Unset". - * By "Flag" the flag in struct b43_rfatt is meant. - * The Value arrays are two-dimensional. The first index - * is the baseband attenuation and the second index - * is the radio attenuation. - * Use b43_get_lo_g_ctl() to retrieve a value from the lists. - */ +/* This struct holds calibrated LO settings for a set of + * Baseband and RF attenuation settings. */ +struct b43_lo_calib { +	/* The set of attenuation values this set of LO +	 * control values is calibrated for. */ +	struct b43_bbatt bbatt; +	struct b43_rfatt rfatt; +	/* The set of control values for the LO. */ +	struct b43_loctl ctl; +	/* The time when these settings were calibrated (in jiffies) */ +	unsigned long calib_time; +	/* List. */ +	struct list_head list; +}; + +/* Size of the DC Lookup Table in 16bit words. */ +#define B43_DC_LT_SIZE		32 + +/* Local Oscillator calibration information */  struct b43_txpower_lo_control { -#define B43_NR_BB	12 -#define B43_NR_RF	16 -	/* LO Control values, with PAD Mixer */ -	struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; -	/* LO Control values, without PAD Mixer */ -	struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; - -	/* Flag to indicate a complete rebuild of the two tables above -	 * to the LO measuring code. */ -	bool rebuild; - -	/* Lists of valid RF and BB attenuation values for this device. */ +	/* Lists of RF and BB attenuation values for this device. +	 * Used for building hardware power control tables. */  	struct b43_rfatt_list rfatt_list;  	struct b43_bbatt_list bbatt_list; +	/* The DC Lookup Table is cached in memory here. +	 * Note that this is only used for Hardware Power Control. */ +	u16 dc_lt[B43_DC_LT_SIZE]; + +	/* List of calibrated control values (struct b43_lo_calib). */ +	struct list_head calib_list; +	/* Last time the power vector was read (jiffies). */ +	unsigned long pwr_vec_read_time; +	/* Last time the txctl values were measured (jiffies). */ +	unsigned long txctl_measured_time; +  	/* Current TX Bias value */  	u8 tx_bias;  	/* Current TX Magnification Value (if used by the device) */  	u8 tx_magn; -	/* GPHY LO is measured. */ -	bool lo_measured; -  	/* Saved device PowerVector */  	u64 power_vector;  }; -/* Measure the BPHY Local Oscillator. */ -void b43_lo_b_measure(struct b43_wldev *dev); -/* Measure the BPHY/GPHY Local Oscillator. */ -void b43_lo_g_measure(struct b43_wldev *dev); +/* Calibration expire timeouts. + * Timeouts must be multiple of 15 seconds. To make sure + * the item really expired when the 15 second timer hits, we + * subtract two additional seconds from the timeout. */ +#define B43_LO_CALIB_EXPIRE	(HZ * (30 - 2)) +#define B43_LO_PWRVEC_EXPIRE	(HZ * (30 - 2)) +#define B43_LO_TXCTL_EXPIRE	(HZ * (180 - 4)) +  /* Adjust the Local Oscillator to the saved attenuation   * and txctl values. @@ -95,18 +76,10 @@ void b43_lo_g_adjust(struct b43_wldev *dev);  void b43_lo_g_adjust_to(struct b43_wldev *dev,  			u16 rfatt, u16 bbatt, u16 tx_control); -/* Mark all possible b43_lo_g_ctl as "unused" */ -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); -/* Mark the b43_lo_g_ctl corresponding to the current - * attenuation values as used. - */ -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -/* Get a reference to a LO Control value pair in the - * TX Power LO Control Array. - */ -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, -				   const struct b43_rfatt *rfatt, -				   const struct b43_bbatt *bbatt); +void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_cleanup(struct b43_wldev *dev); +void b43_lo_g_init(struct b43_wldev *dev);  #endif /* B43_LO_H_ */ diff --git a/package/b43/src/main.c b/package/b43/src/main.c index afb109447..cbb317bb3 100644 --- a/package/b43/src/main.c +++ b/package/b43/src/main.c @@ -38,6 +38,7 @@  #include <linux/wireless.h>  #include <linux/workqueue.h>  #include <linux/skbuff.h> +#include <linux/io.h>  #include <linux/dma-mapping.h>  #include <asm/unaligned.h> @@ -45,7 +46,9 @@  #include "main.h"  #include "debugfs.h"  #include "phy.h" +#include "nphy.h"  #include "dma.h" +#include "pio.h"  #include "sysfs.h"  #include "xmit.h"  #include "lo.h" @@ -57,6 +60,8 @@ MODULE_AUTHOR("Stefano Brivio");  MODULE_AUTHOR("Michael Buesch");  MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); +  static int modparam_bad_frames_preempt;  module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); @@ -75,6 +80,15 @@ static int modparam_nohwcrypt;  module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); +int b43_modparam_qos = 1; +module_param_named(qos, b43_modparam_qos, int, 0444); +MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); + +static int modparam_btcoex = 1; +module_param_named(btcoex, modparam_btcoex, int, 0444); +MODULE_PARM_DESC(btcoex, "Enable Bluetooth coexistance (default on)"); + +  static const struct ssb_device_id b43_ssb_tbl[] = {  	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),  	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), @@ -125,58 +139,143 @@ static struct ieee80211_rate __b43_ratetable[] = {  #define b43_g_ratetable		(__b43_ratetable + 0)  #define b43_g_ratetable_size	12 -#define CHANTAB_ENT(_chanid, _freq) \ -	{							\ -		.center_freq	= (_freq),			\ -		.hw_value	= (_chanid),			\ -	} +#define CHAN4G(_channel, _freq, _flags) {			\ +	.band			= IEEE80211_BAND_2GHZ,		\ +	.center_freq		= (_freq),			\ +	.hw_value		= (_channel),			\ +	.flags			= (_flags),			\ +	.max_antenna_gain	= 0,				\ +	.max_power		= 30,				\ +}  static struct ieee80211_channel b43_2ghz_chantable[] = { -	CHANTAB_ENT(1, 2412), -	CHANTAB_ENT(2, 2417), -	CHANTAB_ENT(3, 2422), -	CHANTAB_ENT(4, 2427), -	CHANTAB_ENT(5, 2432), -	CHANTAB_ENT(6, 2437), -	CHANTAB_ENT(7, 2442), -	CHANTAB_ENT(8, 2447), -	CHANTAB_ENT(9, 2452), -	CHANTAB_ENT(10, 2457), -	CHANTAB_ENT(11, 2462), -	CHANTAB_ENT(12, 2467), -	CHANTAB_ENT(13, 2472), -	CHANTAB_ENT(14, 2484), +	CHAN4G(1, 2412, 0), +	CHAN4G(2, 2417, 0), +	CHAN4G(3, 2422, 0), +	CHAN4G(4, 2427, 0), +	CHAN4G(5, 2432, 0), +	CHAN4G(6, 2437, 0), +	CHAN4G(7, 2442, 0), +	CHAN4G(8, 2447, 0), +	CHAN4G(9, 2452, 0), +	CHAN4G(10, 2457, 0), +	CHAN4G(11, 2462, 0), +	CHAN4G(12, 2467, 0), +	CHAN4G(13, 2472, 0), +	CHAN4G(14, 2484, 0), +}; +#undef CHAN4G + +#define CHAN5G(_channel, _flags) {				\ +	.band			= IEEE80211_BAND_5GHZ,		\ +	.center_freq		= 5000 + (5 * (_channel)),	\ +	.hw_value		= (_channel),			\ +	.flags			= (_flags),			\ +	.max_antenna_gain	= 0,				\ +	.max_power		= 30,				\ +} +static struct ieee80211_channel b43_5ghz_nphy_chantable[] = { +	CHAN5G(32, 0),		CHAN5G(34, 0), +	CHAN5G(36, 0),		CHAN5G(38, 0), +	CHAN5G(40, 0),		CHAN5G(42, 0), +	CHAN5G(44, 0),		CHAN5G(46, 0), +	CHAN5G(48, 0),		CHAN5G(50, 0), +	CHAN5G(52, 0),		CHAN5G(54, 0), +	CHAN5G(56, 0),		CHAN5G(58, 0), +	CHAN5G(60, 0),		CHAN5G(62, 0), +	CHAN5G(64, 0),		CHAN5G(66, 0), +	CHAN5G(68, 0),		CHAN5G(70, 0), +	CHAN5G(72, 0),		CHAN5G(74, 0), +	CHAN5G(76, 0),		CHAN5G(78, 0), +	CHAN5G(80, 0),		CHAN5G(82, 0), +	CHAN5G(84, 0),		CHAN5G(86, 0), +	CHAN5G(88, 0),		CHAN5G(90, 0), +	CHAN5G(92, 0),		CHAN5G(94, 0), +	CHAN5G(96, 0),		CHAN5G(98, 0), +	CHAN5G(100, 0),		CHAN5G(102, 0), +	CHAN5G(104, 0),		CHAN5G(106, 0), +	CHAN5G(108, 0),		CHAN5G(110, 0), +	CHAN5G(112, 0),		CHAN5G(114, 0), +	CHAN5G(116, 0),		CHAN5G(118, 0), +	CHAN5G(120, 0),		CHAN5G(122, 0), +	CHAN5G(124, 0),		CHAN5G(126, 0), +	CHAN5G(128, 0),		CHAN5G(130, 0), +	CHAN5G(132, 0),		CHAN5G(134, 0), +	CHAN5G(136, 0),		CHAN5G(138, 0), +	CHAN5G(140, 0),		CHAN5G(142, 0), +	CHAN5G(144, 0),		CHAN5G(145, 0), +	CHAN5G(146, 0),		CHAN5G(147, 0), +	CHAN5G(148, 0),		CHAN5G(149, 0), +	CHAN5G(150, 0),		CHAN5G(151, 0), +	CHAN5G(152, 0),		CHAN5G(153, 0), +	CHAN5G(154, 0),		CHAN5G(155, 0), +	CHAN5G(156, 0),		CHAN5G(157, 0), +	CHAN5G(158, 0),		CHAN5G(159, 0), +	CHAN5G(160, 0),		CHAN5G(161, 0), +	CHAN5G(162, 0),		CHAN5G(163, 0), +	CHAN5G(164, 0),		CHAN5G(165, 0), +	CHAN5G(166, 0),		CHAN5G(168, 0), +	CHAN5G(170, 0),		CHAN5G(172, 0), +	CHAN5G(174, 0),		CHAN5G(176, 0), +	CHAN5G(178, 0),		CHAN5G(180, 0), +	CHAN5G(182, 0),		CHAN5G(184, 0), +	CHAN5G(186, 0),		CHAN5G(188, 0), +	CHAN5G(190, 0),		CHAN5G(192, 0), +	CHAN5G(194, 0),		CHAN5G(196, 0), +	CHAN5G(198, 0),		CHAN5G(200, 0), +	CHAN5G(202, 0),		CHAN5G(204, 0), +	CHAN5G(206, 0),		CHAN5G(208, 0), +	CHAN5G(210, 0),		CHAN5G(212, 0), +	CHAN5G(214, 0),		CHAN5G(216, 0), +	CHAN5G(218, 0),		CHAN5G(220, 0), +	CHAN5G(222, 0),		CHAN5G(224, 0), +	CHAN5G(226, 0),		CHAN5G(228, 0),  }; -#ifdef NOTYET -static struct ieee80211_channel b43_5ghz_chantable[] = { -	CHANTAB_ENT(36, 5180), -	CHANTAB_ENT(40, 5200), -	CHANTAB_ENT(44, 5220), -	CHANTAB_ENT(48, 5240), -	CHANTAB_ENT(52, 5260), -	CHANTAB_ENT(56, 5280), -	CHANTAB_ENT(60, 5300), -	CHANTAB_ENT(64, 5320), -	CHANTAB_ENT(149, 5745), -	CHANTAB_ENT(153, 5765), -	CHANTAB_ENT(157, 5785), -	CHANTAB_ENT(161, 5805), -	CHANTAB_ENT(165, 5825), +static struct ieee80211_channel b43_5ghz_aphy_chantable[] = { +	CHAN5G(34, 0),		CHAN5G(36, 0), +	CHAN5G(38, 0),		CHAN5G(40, 0), +	CHAN5G(42, 0),		CHAN5G(44, 0), +	CHAN5G(46, 0),		CHAN5G(48, 0), +	CHAN5G(52, 0),		CHAN5G(56, 0), +	CHAN5G(60, 0),		CHAN5G(64, 0), +	CHAN5G(100, 0),		CHAN5G(104, 0), +	CHAN5G(108, 0),		CHAN5G(112, 0), +	CHAN5G(116, 0),		CHAN5G(120, 0), +	CHAN5G(124, 0),		CHAN5G(128, 0), +	CHAN5G(132, 0),		CHAN5G(136, 0), +	CHAN5G(140, 0),		CHAN5G(149, 0), +	CHAN5G(153, 0),		CHAN5G(157, 0), +	CHAN5G(161, 0),		CHAN5G(165, 0), +	CHAN5G(184, 0),		CHAN5G(188, 0), +	CHAN5G(192, 0),		CHAN5G(196, 0), +	CHAN5G(200, 0),		CHAN5G(204, 0), +	CHAN5G(208, 0),		CHAN5G(212, 0), +	CHAN5G(216, 0), +}; +#undef CHAN5G + +static struct ieee80211_supported_band b43_band_5GHz_nphy = { +	.band		= IEEE80211_BAND_5GHZ, +	.channels	= b43_5ghz_nphy_chantable, +	.n_channels	= ARRAY_SIZE(b43_5ghz_nphy_chantable), +	.bitrates	= b43_a_ratetable, +	.n_bitrates	= b43_a_ratetable_size,  }; -static struct ieee80211_supported_band b43_band_5GHz = { -	.channels = b43_5ghz_chantable, -	.n_channels = ARRAY_SIZE(b43_5ghz_chantable), -	.bitrates = b43_a_ratetable, -	.n_bitrates = b43_a_ratetable_size, +static struct ieee80211_supported_band b43_band_5GHz_aphy = { +	.band		= IEEE80211_BAND_5GHZ, +	.channels	= b43_5ghz_aphy_chantable, +	.n_channels	= ARRAY_SIZE(b43_5ghz_aphy_chantable), +	.bitrates	= b43_a_ratetable, +	.n_bitrates	= b43_a_ratetable_size,  }; -#endif  static struct ieee80211_supported_band b43_band_2GHz = { -	.channels = b43_2ghz_chantable, -	.n_channels = ARRAY_SIZE(b43_2ghz_chantable), -	.bitrates = b43_g_ratetable, -	.n_bitrates = b43_g_ratetable_size, +	.band		= IEEE80211_BAND_2GHZ, +	.channels	= b43_2ghz_chantable, +	.n_channels	= ARRAY_SIZE(b43_2ghz_chantable), +	.bitrates	= b43_g_ratetable, +	.n_bitrates	= b43_g_ratetable_size,  };  static void b43_wireless_core_exit(struct b43_wldev *dev); @@ -377,24 +476,30 @@ out:  }  /* Read HostFlags */ -u32 b43_hf_read(struct b43_wldev * dev) +u64 b43_hf_read(struct b43_wldev * dev)  { -	u32 ret; +	u64 ret;  	ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);  	ret <<= 16; +	ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI); +	ret <<= 16;  	ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);  	return ret;  }  /* Write HostFlags */ -void b43_hf_write(struct b43_wldev *dev, u32 value) +void b43_hf_write(struct b43_wldev *dev, u64 value)  { -	b43_shm_write16(dev, B43_SHM_SHARED, -			B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF)); -	b43_shm_write16(dev, B43_SHM_SHARED, -			B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16)); +	u16 lo, mi, hi; + +	lo = (value & 0x00000000FFFFULL); +	mi = (value & 0x0000FFFF0000ULL) >> 16; +	hi = (value & 0xFFFF00000000ULL) >> 32; +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo); +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi); +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);  }  void b43_tsf_read(struct b43_wldev *dev, u64 * tsf) @@ -624,6 +729,7 @@ static void b43_synchronize_irq(struct b43_wldev *dev)   */  void b43_dummy_transmission(struct b43_wldev *dev)  { +	struct b43_wl *wl = dev->wl;  	struct b43_phy *phy = &dev->phy;  	unsigned int i, max_loop;  	u16 value; @@ -650,6 +756,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)  		return;  	} +	spin_lock_irq(&wl->irq_lock); +	write_lock(&wl->tx_lock); +  	for (i = 0; i < 5; i++)  		b43_ram_write(dev, i * 4, buffer[i]); @@ -690,6 +799,9 @@ void b43_dummy_transmission(struct b43_wldev *dev)  	}  	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)  		b43_radio_write16(dev, 0x0051, 0x0037); + +	write_unlock(&wl->tx_lock); +	spin_unlock_irq(&wl->irq_lock);  }  static void key_write(struct b43_wldev *dev, @@ -919,7 +1031,18 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)  /* Turn the Analog ON/OFF */  static void b43_switch_analog(struct b43_wldev *dev, int on)  { -	b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +	switch (dev->phy.type) { +	case B43_PHYTYPE_A: +	case B43_PHYTYPE_G: +		b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4); +		break; +	case B43_PHYTYPE_N: +		b43_phy_write(dev, B43_NPHY_AFECTL_OVER, +			      on ? 0 : 0x7FFF); +		break; +	default: +		B43_WARN_ON(1); +	}  }  void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags) @@ -1059,10 +1182,10 @@ static void handle_irq_noise(struct b43_wldev *dev)  	/* Get the noise samples. */  	B43_WARN_ON(dev->noisecalc.nr_samples >= 8);  	i = dev->noisecalc.nr_samples; -	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); -	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); -	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); -	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); +	noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); +	noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); +	noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); +	noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);  	dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];  	dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];  	dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; @@ -1169,22 +1292,107 @@ static void b43_write_template_common(struct b43_wldev *dev,  			size + sizeof(struct b43_plcp_hdr6));  } +/* Check if the use of the antenna that ieee80211 told us to + * use is possible. This will fall back to DEFAULT. + * "antenna_nr" is the antenna identifier we got from ieee80211. */ +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, +				  u8 antenna_nr) +{ +	u8 antenna_mask; + +	if (antenna_nr == 0) { +		/* Zero means "use default antenna". That's always OK. */ +		return 0; +	} + +	/* Get the mask of available antennas. */ +	if (dev->phy.gmode) +		antenna_mask = dev->dev->bus->sprom.ant_available_bg; +	else +		antenna_mask = dev->dev->bus->sprom.ant_available_a; + +	if (!(antenna_mask & (1 << (antenna_nr - 1)))) { +		/* This antenna is not available. Fall back to default. */ +		return 0; +	} + +	return antenna_nr; +} + +static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) +{ +	antenna = b43_ieee80211_antenna_sanitize(dev, antenna); +	switch (antenna) { +	case 0:		/* default/diversity */ +		return B43_ANTENNA_DEFAULT; +	case 1:		/* Antenna 0 */ +		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; +	} +} + +/* Convert a b43 antenna number value to the PHY TX control value. */ +static u16 b43_antenna_to_phyctl(int antenna) +{ +	switch (antenna) { +	case B43_ANTENNA0: +		return B43_TXH_PHY_ANT0; +	case B43_ANTENNA1: +		return B43_TXH_PHY_ANT1; +	case B43_ANTENNA2: +		return B43_TXH_PHY_ANT2; +	case B43_ANTENNA3: +		return B43_TXH_PHY_ANT3; +	case B43_ANTENNA_AUTO: +		return B43_TXH_PHY_ANT01AUTO; +	} +	B43_WARN_ON(1); +	return 0; +} +  static void b43_write_beacon_template(struct b43_wldev *dev,  				      u16 ram_offset, -				      u16 shm_size_offset, u8 rate) +				      u16 shm_size_offset)  {  	unsigned int i, len, variable_len;  	const struct ieee80211_mgmt *bcn;  	const u8 *ie;  	bool tim_found = 0; +	unsigned int rate; +	u16 ctl; +	int antenna; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);  	bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);  	len = min((size_t) dev->wl->current_beacon->len,  		  0x200 - sizeof(struct b43_plcp_hdr6)); +	rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;  	b43_write_template_common(dev, (const u8 *)bcn,  				  len, ram_offset, shm_size_offset, rate); +	/* Write the PHY TX control parameters. */ +	antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); +	antenna = b43_antenna_to_phyctl(antenna); +	ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); +	/* We can't send beacons with short preamble. Would get PHY errors. */ +	ctl &= ~B43_TXH_PHY_SHORTPRMBL; +	ctl &= ~B43_TXH_PHY_ANT; +	ctl &= ~B43_TXH_PHY_ENC; +	ctl |= antenna; +	if (b43_is_cck_rate(rate)) +		ctl |= B43_TXH_PHY_ENC_CCK; +	else +		ctl |= B43_TXH_PHY_ENC_OFDM; +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); +  	/* Find the position of the TIM and the DTIM_period value  	 * and write them to SHM. */  	ie = bcn->u.beacon.variable; @@ -1225,7 +1433,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev,  		b43warn(dev->wl, "Did not find a valid TIM IE in "  			"the beacon template packet. AP or IBSS operation "  			"may be broken.\n"); -	} +	} else +		b43dbg(dev->wl, "Updated beacon template\n");  }  static void b43_write_probe_resp_plcp(struct b43_wldev *dev, @@ -1335,6 +1544,73 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,  	kfree(probe_resp_data);  } +static void handle_irq_beacon(struct b43_wldev *dev) +{ +	struct b43_wl *wl = dev->wl; +	u32 cmd, beacon0_valid, beacon1_valid; + +	if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) +		return; + +	/* This is the bottom half of the asynchronous beacon update. */ + +	/* Ignore interrupt in the future. */ +	dev->irq_savedstate &= ~B43_IRQ_BEACON; + +	cmd = b43_read32(dev, B43_MMIO_MACCMD); +	beacon0_valid = (cmd & B43_MACCMD_BEACON0_VALID); +	beacon1_valid = (cmd & B43_MACCMD_BEACON1_VALID); + +	/* Schedule interrupt manually, if busy. */ +	if (beacon0_valid && beacon1_valid) { +		b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); +		dev->irq_savedstate |= B43_IRQ_BEACON; +		return; +	} + +	if (!beacon0_valid) { +		if (!wl->beacon0_uploaded) { +			b43_write_beacon_template(dev, 0x68, 0x18); +			b43_write_probe_resp_template(dev, 0x268, 0x4A, +						      &__b43_ratetable[3]); +			wl->beacon0_uploaded = 1; +		} +		cmd = b43_read32(dev, B43_MMIO_MACCMD); +		cmd |= B43_MACCMD_BEACON0_VALID; +		b43_write32(dev, B43_MMIO_MACCMD, cmd); +	} else if (!beacon1_valid) { +		if (!wl->beacon1_uploaded) { +			b43_write_beacon_template(dev, 0x468, 0x1A); +			wl->beacon1_uploaded = 1; +		} +		cmd = b43_read32(dev, B43_MMIO_MACCMD); +		cmd |= B43_MACCMD_BEACON1_VALID; +		b43_write32(dev, B43_MMIO_MACCMD, cmd); +	} +} + +static void b43_beacon_update_trigger_work(struct work_struct *work) +{ +	struct b43_wl *wl = container_of(work, struct b43_wl, +					 beacon_update_trigger); +	struct b43_wldev *dev; + +	mutex_lock(&wl->mutex); +	dev = wl->current_dev; +	if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { +		spin_lock_irq(&wl->irq_lock); +		/* update beacon right away or defer to irq */ +		dev->irq_savedstate = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); +		handle_irq_beacon(dev); +		/* The handler might have updated the IRQ mask. */ +		b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, +			    dev->irq_savedstate); +		mmiowb(); +		spin_unlock_irq(&wl->irq_lock); +	} +	mutex_unlock(&wl->mutex); +} +  /* Asynchronously update the packet templates in template RAM.   * Locking: Requires wl->irq_lock to be locked. */  static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) @@ -1350,6 +1626,7 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)  	wl->current_beacon = beacon;  	wl->beacon0_uploaded = 0;  	wl->beacon1_uploaded = 0; +	queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);  }  static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) @@ -1375,49 +1652,110 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)  {  	b43_time_lock(dev);  	if (dev->dev->id.revision >= 3) { -		b43_write32(dev, 0x188, (beacon_int << 16)); +		b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16)); +		b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));  	} else {  		b43_write16(dev, 0x606, (beacon_int >> 6));  		b43_write16(dev, 0x610, beacon_int);  	}  	b43_time_unlock(dev); +	b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);  } -static void handle_irq_beacon(struct b43_wldev *dev) +static void b43_handle_firmware_panic(struct b43_wldev *dev)  { -	struct b43_wl *wl = dev->wl; -	u32 cmd; +	u16 reason; -	if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) -		return; +	/* Read the register that contains the reason code for the panic. */ +	reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG); +	b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason); -	/* This is the bottom half of the asynchronous beacon update. */ - -	cmd = b43_read32(dev, B43_MMIO_MACCMD); -	if (!(cmd & B43_MACCMD_BEACON0_VALID)) { -		if (!wl->beacon0_uploaded) { -			b43_write_beacon_template(dev, 0x68, 0x18, -						  B43_CCK_RATE_1MB); -			b43_write_probe_resp_template(dev, 0x268, 0x4A, -						      &__b43_ratetable[3]); -			wl->beacon0_uploaded = 1; -		} -		cmd |= B43_MACCMD_BEACON0_VALID; -	} -	if (!(cmd & B43_MACCMD_BEACON1_VALID)) { -		if (!wl->beacon1_uploaded) { -			b43_write_beacon_template(dev, 0x468, 0x1A, -						  B43_CCK_RATE_1MB); -			wl->beacon1_uploaded = 1; -		} -		cmd |= B43_MACCMD_BEACON1_VALID; +	switch (reason) { +	default: +		b43dbg(dev->wl, "The panic reason is unknown.\n"); +		/* fallthrough */ +	case B43_FWPANIC_DIE: +		/* Do not restart the controller or firmware. +		 * The device is nonfunctional from now on. +		 * Restarting would result in this panic to trigger again, +		 * so we avoid that recursion. */ +		break; +	case B43_FWPANIC_RESTART: +		b43_controller_restart(dev, "Microcode panic"); +		break;  	} -	b43_write32(dev, B43_MMIO_MACCMD, cmd);  }  static void handle_irq_ucode_debug(struct b43_wldev *dev)  { -	//TODO +	unsigned int i, cnt; +	u16 reason, marker_id, marker_line; +	__le16 *buf; + +	/* The proprietary firmware doesn't have this IRQ. */ +	if (!dev->fw.opensource) +		return; + +	/* Read the register that contains the reason code for this IRQ. */ +	reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG); + +	switch (reason) { +	case B43_DEBUGIRQ_PANIC: +		b43_handle_firmware_panic(dev); +		break; +	case B43_DEBUGIRQ_DUMP_SHM: +		if (!B43_DEBUG) +			break; /* Only with driver debugging enabled. */ +		buf = kmalloc(4096, GFP_ATOMIC); +		if (!buf) { +			b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n"); +			goto out; +		} +		for (i = 0; i < 4096; i += 2) { +			u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i); +			buf[i / 2] = cpu_to_le16(tmp); +		} +		b43info(dev->wl, "Shared memory dump:\n"); +		print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, +			       16, 2, buf, 4096, 1); +		kfree(buf); +		break; +	case B43_DEBUGIRQ_DUMP_REGS: +		if (!B43_DEBUG) +			break; /* Only with driver debugging enabled. */ +		b43info(dev->wl, "Microcode register dump:\n"); +		for (i = 0, cnt = 0; i < 64; i++) { +			u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i); +			if (cnt == 0) +				printk(KERN_INFO); +			printk("r%02u: 0x%04X  ", i, tmp); +			cnt++; +			if (cnt == 6) { +				printk("\n"); +				cnt = 0; +			} +		} +		printk("\n"); +		break; +	case B43_DEBUGIRQ_MARKER: +		if (!B43_DEBUG) +			break; /* Only with driver debugging enabled. */ +		marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH, +					   B43_MARKER_ID_REG); +		marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH, +					     B43_MARKER_LINE_REG); +		b43info(dev->wl, "The firmware just executed the MARKER(%u) " +			"at line number %u\n", +			marker_id, marker_line); +		break; +	default: +		b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", +		       reason); +	} +out: +	/* Acknowledge the debug-IRQ, so the firmware can continue. */ +	b43_shm_write16(dev, B43_SHM_SCRATCH, +			B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);  }  /* Interrupt handler bottom-half */ @@ -1494,12 +1832,15 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)  		handle_irq_noise(dev);  	/* Check the DMA reason registers for received data. */ -	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) -		b43_dma_rx(dev->dma.rx_ring0); -	if (dma_reason[3] & B43_DMAIRQ_RX_DONE) -		b43_dma_rx(dev->dma.rx_ring3); +	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { +		if (b43_using_pio_transfers(dev)) +			b43_pio_rx(dev->pio.rx_queue); +		else +			b43_dma_rx(dev->dma.rx_ring); +	}  	B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);  	B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); +	B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);  	B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);  	B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); @@ -1601,7 +1942,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)  static int do_request_fw(struct b43_wldev *dev,  			 const char *name, -			 struct b43_firmware_file *fw) +			 struct b43_firmware_file *fw, +			 bool silent)  {  	char path[sizeof(modparam_fwpostfix) + 32];  	const struct firmware *blob; @@ -1625,9 +1967,15 @@ static int do_request_fw(struct b43_wldev *dev,  		 "b43%s/%s.fw",  		 modparam_fwpostfix, name);  	err = request_firmware(&blob, path, dev->dev->dev); -	if (err) { -		b43err(dev->wl, "Firmware file \"%s\" not found " -		       "or load failed.\n", path); +	if (err == -ENOENT) { +		if (!silent) { +			b43err(dev->wl, "Firmware file \"%s\" not found\n", +			       path); +		} +		return err; +	} else if (err) { +		b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", +		       path, err);  		return err;  	}  	if (blob->size < sizeof(struct b43_fw_header)) @@ -1678,7 +2026,7 @@ static int b43_request_firmware(struct b43_wldev *dev)  		filename = "ucode13";  	else  		goto err_no_ucode; -	err = do_request_fw(dev, filename, &fw->ucode); +	err = do_request_fw(dev, filename, &fw->ucode, 0);  	if (err)  		goto err_load; @@ -1689,8 +2037,13 @@ static int b43_request_firmware(struct b43_wldev *dev)  		filename = NULL;  	else  		goto err_no_pcm; -	err = do_request_fw(dev, filename, &fw->pcm); -	if (err) +	fw->pcm_request_failed = 0; +	err = do_request_fw(dev, filename, &fw->pcm, 1); +	if (err == -ENOENT) { +		/* We did not find a PCM file? Not fatal, but +		 * core rev <= 10 must do without hwcrypto then. */ +		fw->pcm_request_failed = 1; +	} else if (err)  		goto err_load;  	/* Get initvals */ @@ -1708,7 +2061,7 @@ static int b43_request_firmware(struct b43_wldev *dev)  		if ((rev >= 5) && (rev <= 10))  			filename = "b0g0initvals5";  		else if (rev >= 13) -			filename = "lp0initvals13"; +			filename = "b0g0initvals13";  		else  			goto err_no_initvals;  		break; @@ -1721,7 +2074,7 @@ static int b43_request_firmware(struct b43_wldev *dev)  	default:  		goto err_no_initvals;  	} -	err = do_request_fw(dev, filename, &fw->initvals); +	err = do_request_fw(dev, filename, &fw->initvals, 0);  	if (err)  		goto err_load; @@ -1755,7 +2108,7 @@ static int b43_request_firmware(struct b43_wldev *dev)  	default:  		goto err_no_initvals;  	} -	err = do_request_fw(dev, filename, &fw->initvals_band); +	err = do_request_fw(dev, filename, &fw->initvals_band, 0);  	if (err)  		goto err_load; @@ -1872,14 +2225,28 @@ static int b43_upload_microcode(struct b43_wldev *dev)  		err = -EOPNOTSUPP;  		goto error;  	} -	b43dbg(dev->wl, "Loading firmware version %u.%u " -	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", -	       fwrev, fwpatch, -	       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, -	       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); -  	dev->fw.rev = fwrev;  	dev->fw.patch = fwpatch; +	dev->fw.opensource = (fwdate == 0xFFFF); + +	if (dev->fw.opensource) { +		/* Patchlevel info is encoded in the "time" field. */ +		dev->fw.patch = fwtime; +		b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", +			dev->fw.rev, dev->fw.patch, +			dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); +	} else { +		b43info(dev->wl, "Loading firmware version %u.%u " +			"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", +			fwrev, fwpatch, +			(fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, +			(fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); +		if (dev->fw.pcm_request_failed) { +			b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. " +				"Hardware accelerated cryptography is disabled.\n"); +			b43_print_fw_helptext(dev->wl, 0); +		} +	}  	if (b43_is_old_txhdr_format(dev)) {  		b43warn(dev->wl, "You are using an old firmware image. " @@ -1926,7 +2293,7 @@ static int b43_write_initvals(struct b43_wldev *dev,  				goto err_format;  			array_size -= sizeof(iv->data.d32); -			value = be32_to_cpu(get_unaligned(&iv->data.d32)); +			value = get_unaligned_be32(&iv->data.d32);  			b43_write32(dev, offset, value);  			iv = (const struct b43_iv *)((const uint8_t *)iv + @@ -2060,7 +2427,6 @@ void b43_mac_enable(struct b43_wldev *dev)  {  	dev->mac_suspended--;  	B43_WARN_ON(dev->mac_suspended < 0); -	B43_WARN_ON(irqs_disabled());  	if (dev->mac_suspended == 0) {  		b43_write32(dev, B43_MMIO_MACCTL,  			    b43_read32(dev, B43_MMIO_MACCTL) @@ -2071,11 +2437,6 @@ void b43_mac_enable(struct b43_wldev *dev)  		b43_read32(dev, B43_MMIO_MACCTL);  		b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);  		b43_power_saving_ctl_bits(dev, 0); - -		/* Re-enable IRQs. */ -		spin_lock_irq(&dev->wl->irq_lock); -		b43_interrupt_enable(dev, dev->irq_savedstate); -		spin_unlock_irq(&dev->wl->irq_lock);  	}  } @@ -2086,24 +2447,22 @@ void b43_mac_suspend(struct b43_wldev *dev)  	u32 tmp;  	might_sleep(); -	B43_WARN_ON(irqs_disabled());  	B43_WARN_ON(dev->mac_suspended < 0);  	if (dev->mac_suspended == 0) { -		/* Mask IRQs before suspending MAC. Otherwise -		 * the MAC stays busy and won't suspend. */ -		spin_lock_irq(&dev->wl->irq_lock); -		tmp = b43_interrupt_disable(dev, B43_IRQ_ALL); -		spin_unlock_irq(&dev->wl->irq_lock); -		b43_synchronize_irq(dev); -		dev->irq_savedstate = tmp; -  		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);  		b43_write32(dev, B43_MMIO_MACCTL,  			    b43_read32(dev, B43_MMIO_MACCTL)  			    & ~B43_MACCTL_ENABLED);  		/* force pci to flush the write */  		b43_read32(dev, B43_MMIO_MACCTL); +		for (i = 35; i; i--) { +			tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); +			if (tmp & B43_IRQ_MAC_SUSPENDED) +				goto out; +			udelay(10); +		} +		/* Hm, it seems this will take some time. Use msleep(). */  		for (i = 40; i; i--) {  			tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);  			if (tmp & B43_IRQ_MAC_SUSPENDED) @@ -2209,38 +2568,28 @@ static void b43_rate_memory_init(struct b43_wldev *dev)  	}  } +/* Set the default values for the PHY TX Control Words. */ +static void b43_set_phytxctl_defaults(struct b43_wldev *dev) +{ +	u16 ctl = 0; + +	ctl |= B43_TXH_PHY_ENC_CCK; +	ctl |= B43_TXH_PHY_ANT01AUTO; +	ctl |= B43_TXH_PHY_TXPWR; + +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl); +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, ctl); +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, ctl); +} +  /* Set the TX-Antenna for management frames sent by firmware. */  static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)  { -	u16 ant = 0; +	u16 ant;  	u16 tmp; -	switch (antenna) { -	case B43_ANTENNA0: -		ant |= B43_TXH_PHY_ANT0; -		break; -	case B43_ANTENNA1: -		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_TXH_PHY_ANT01AUTO; -		break; -	default: -		B43_WARN_ON(1); -	} - -	/* FIXME We also need to set the other flags of the PHY control field somewhere. */ +	ant = b43_antenna_to_phyctl(antenna); -	/* For Beacons */ -	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); -	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_TXH_PHY_ANT) | ant; @@ -2256,6 +2605,7 @@ static void b43_chip_exit(struct b43_wldev *dev)  {  	b43_radio_turn_off(dev, 1);  	b43_gpio_cleanup(dev); +	b43_lo_g_cleanup(dev);  	/* firmware is released later */  } @@ -2362,28 +2712,12 @@ err_gpio_clean:  	return err;  } -static void b43_periodic_every120sec(struct b43_wldev *dev) -{ -	struct b43_phy *phy = &dev->phy; - -	if (phy->type != B43_PHYTYPE_G || phy->rev < 2) -		return; - -	b43_mac_suspend(dev); -	b43_lo_g_measure(dev); -	b43_mac_enable(dev); -	if (b43_has_hardware_pctl(phy)) -		b43_lo_g_ctl_mark_all_unused(dev); -} -  static void b43_periodic_every60sec(struct b43_wldev *dev)  {  	struct b43_phy *phy = &dev->phy;  	if (phy->type != B43_PHYTYPE_G)  		return; -	if (!b43_has_hardware_pctl(phy)) -		b43_lo_g_ctl_mark_all_unused(dev);  	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {  		b43_mac_suspend(dev);  		b43_calc_nrssi_slope(dev); @@ -2435,6 +2769,7 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)  		}  	}  	b43_phy_xmitpower(dev);	//FIXME: unless scanning? +	b43_lo_g_maintanance_work(dev);  	//TODO for APHY (temperature?)  	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); @@ -2446,8 +2781,6 @@ static void do_periodic_work(struct b43_wldev *dev)  	unsigned int state;  	state = dev->periodic_state; -	if (state % 8 == 0) -		b43_periodic_every120sec(dev);  	if (state % 4 == 0)  		b43_periodic_every60sec(dev);  	if (state % 2 == 0) @@ -2595,29 +2928,211 @@ static int b43_rng_init(struct b43_wl *wl)  }  static int b43_op_tx(struct ieee80211_hw *hw, -		     struct sk_buff *skb, -		     struct ieee80211_tx_control *ctl) +		     struct sk_buff *skb)  {  	struct b43_wl *wl = hw_to_b43_wl(hw);  	struct b43_wldev *dev = wl->current_dev; -	int err = -ENODEV; +	unsigned long flags; +	int err; +	if (unlikely(skb->len < 2 + 2 + 6)) { +		/* Too short, this can't be a valid frame. */ +		dev_kfree_skb_any(skb); +		return NETDEV_TX_OK; +	} +	B43_WARN_ON(skb_shinfo(skb)->nr_frags);  	if (unlikely(!dev)) -		goto out; -	if (unlikely(b43_status(dev) < B43_STAT_STARTED)) -		goto out; -	/* DMA-TX is done without a global lock. */ -	err = b43_dma_tx(dev, skb, ctl); -out: +		return NETDEV_TX_BUSY; + +	/* Transmissions on seperate queues can run concurrently. */ +	read_lock_irqsave(&wl->tx_lock, flags); + +	err = -ENODEV; +	if (likely(b43_status(dev) >= B43_STAT_STARTED)) { +		if (b43_using_pio_transfers(dev)) +			err = b43_pio_tx(dev, skb); +		else +			err = b43_dma_tx(dev, skb); +	} + +	read_unlock_irqrestore(&wl->tx_lock, flags); +  	if (unlikely(err))  		return NETDEV_TX_BUSY;  	return NETDEV_TX_OK;  } -static int b43_op_conf_tx(struct ieee80211_hw *hw, -			  int queue, +/* Locking: wl->irq_lock */ +static void b43_qos_params_upload(struct b43_wldev *dev, +				  const struct ieee80211_tx_queue_params *p, +				  u16 shm_offset) +{ +	u16 params[B43_NR_QOSPARAMS]; +	int cw_min, cw_max, aifs, bslots, tmp; +	unsigned int i; + +	const u16 aCWmin = 0x0001; +	const u16 aCWmax = 0x03FF; + +	/* Calculate the default values for the parameters, if needed. */ +	switch (shm_offset) { +	case B43_QOS_VOICE: +		aifs = (p->aifs == -1) ? 2 : p->aifs; +		cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; +		cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; +		break; +	case B43_QOS_VIDEO: +		aifs = (p->aifs == -1) ? 2 : p->aifs; +		cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; +		cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; +		break; +	case B43_QOS_BESTEFFORT: +		aifs = (p->aifs == -1) ? 3 : p->aifs; +		cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; +		cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; +		break; +	case B43_QOS_BACKGROUND: +		aifs = (p->aifs == -1) ? 7 : p->aifs; +		cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; +		cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; +		break; +	default: +		B43_WARN_ON(1); +		return; +	} +	if (cw_min <= 0) +		cw_min = aCWmin; +	if (cw_max <= 0) +		cw_max = aCWmin; +	bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; + +	memset(¶ms, 0, sizeof(params)); + +	params[B43_QOSPARAM_TXOP] = p->txop * 32; +	params[B43_QOSPARAM_CWMIN] = cw_min; +	params[B43_QOSPARAM_CWMAX] = cw_max; +	params[B43_QOSPARAM_CWCUR] = cw_min; +	params[B43_QOSPARAM_AIFS] = aifs; +	params[B43_QOSPARAM_BSLOTS] = bslots; +	params[B43_QOSPARAM_REGGAP] = bslots + aifs; + +	for (i = 0; i < ARRAY_SIZE(params); i++) { +		if (i == B43_QOSPARAM_STATUS) { +			tmp = b43_shm_read16(dev, B43_SHM_SHARED, +					     shm_offset + (i * 2)); +			/* Mark the parameters as updated. */ +			tmp |= 0x100; +			b43_shm_write16(dev, B43_SHM_SHARED, +					shm_offset + (i * 2), +					tmp); +		} else { +			b43_shm_write16(dev, B43_SHM_SHARED, +					shm_offset + (i * 2), +					params[i]); +		} +	} +} + +/* Update the QOS parameters in hardware. */ +static void b43_qos_update(struct b43_wldev *dev) +{ +	struct b43_wl *wl = dev->wl; +	struct b43_qos_params *params; +	unsigned long flags; +	unsigned int i; + +	/* Mapping of mac80211 queues to b43 SHM offsets. */ +	static const u16 qos_shm_offsets[] = { +		[0] = B43_QOS_VOICE, +		[1] = B43_QOS_VIDEO, +		[2] = B43_QOS_BESTEFFORT, +		[3] = B43_QOS_BACKGROUND, +	}; +	BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); + +	b43_mac_suspend(dev); +	spin_lock_irqsave(&wl->irq_lock, flags); + +	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { +		params = &(wl->qos_params[i]); +		if (params->need_hw_update) { +			b43_qos_params_upload(dev, &(params->p), +					      qos_shm_offsets[i]); +			params->need_hw_update = 0; +		} +	} + +	spin_unlock_irqrestore(&wl->irq_lock, flags); +	b43_mac_enable(dev); +} + +static void b43_qos_clear(struct b43_wl *wl) +{ +	struct b43_qos_params *params; +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { +		params = &(wl->qos_params[i]); + +		memset(&(params->p), 0, sizeof(params->p)); +		params->p.aifs = -1; +		params->need_hw_update = 1; +	} +} + +/* Initialize the core's QOS capabilities */ +static void b43_qos_init(struct b43_wldev *dev) +{ +	struct b43_wl *wl = dev->wl; +	unsigned int i; + +	/* Upload the current QOS parameters. */ +	for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) +		wl->qos_params[i].need_hw_update = 1; +	b43_qos_update(dev); + +	/* Enable QOS support. */ +	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); +	b43_write16(dev, B43_MMIO_IFSCTL, +		    b43_read16(dev, B43_MMIO_IFSCTL) +		    | B43_MMIO_IFSCTL_USE_EDCF); +} + +static void b43_qos_update_work(struct work_struct *work) +{ +	struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); +	struct b43_wldev *dev; + +	mutex_lock(&wl->mutex); +	dev = wl->current_dev; +	if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) +		b43_qos_update(dev); +	mutex_unlock(&wl->mutex); +} + +static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,  			  const struct ieee80211_tx_queue_params *params)  { +	struct b43_wl *wl = hw_to_b43_wl(hw); +	unsigned long flags; +	unsigned int queue = (unsigned int)_queue; +	struct b43_qos_params *p; + +	if (queue >= ARRAY_SIZE(wl->qos_params)) { +		/* Queue not available or don't support setting +		 * params on this queue. Return success to not +		 * confuse mac80211. */ +		return 0; +	} + +	spin_lock_irqsave(&wl->irq_lock, flags); +	p = &(wl->qos_params[queue]); +	memcpy(&(p->p), params, sizeof(p->p)); +	p->need_hw_update = 1; +	spin_unlock_irqrestore(&wl->irq_lock, flags); + +	queue_work(hw->workqueue, &wl->qos_update_work); +  	return 0;  } @@ -2633,7 +3148,10 @@ static int b43_op_get_tx_stats(struct ieee80211_hw *hw,  		goto out;  	spin_lock_irqsave(&wl->irq_lock, flags);  	if (likely(b43_status(dev) >= B43_STAT_STARTED)) { -		b43_dma_get_tx_stats(dev, stats); +		if (b43_using_pio_transfers(dev)) +			b43_pio_get_tx_stats(dev, stats); +		else +			b43_dma_get_tx_stats(dev, stats);  		err = 0;  	}  	spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -2654,45 +3172,6 @@ static int b43_op_get_stats(struct ieee80211_hw *hw,  	return 0;  } -static const char *phymode_to_string(unsigned int phymode) -{ -	switch (phymode) { -	case B43_PHYMODE_A: -		return "A"; -	case B43_PHYMODE_B: -		return "B"; -	case B43_PHYMODE_G: -		return "G"; -	default: -		B43_WARN_ON(1); -	} -	return ""; -} - -static int find_wldev_for_phymode(struct b43_wl *wl, -				  unsigned int phymode, -				  struct b43_wldev **dev, bool * gmode) -{ -	struct b43_wldev *d; - -	list_for_each_entry(d, &wl->devlist, list) { -		if (d->phy.possible_phymodes & phymode) { -			/* Ok, this device supports the PHY-mode. -			 * Now figure out how the gmode bit has to be -			 * set to support it. */ -			if (phymode == B43_PHYMODE_A) -				*gmode = 0; -			else -				*gmode = 1; -			*dev = d; - -			return 0; -		} -	} - -	return -ESRCH; -} -  static void b43_put_phy_into_reset(struct b43_wldev *dev)  {  	struct ssb_device *sdev = dev->dev; @@ -2712,28 +3191,64 @@ static void b43_put_phy_into_reset(struct b43_wldev *dev)  	msleep(1);  } +static const char * band_to_string(enum ieee80211_band band) +{ +	switch (band) { +	case IEEE80211_BAND_5GHZ: +		return "5"; +	case IEEE80211_BAND_2GHZ: +		return "2.4"; +	default: +		break; +	} +	B43_WARN_ON(1); +	return ""; +} +  /* Expects wl->mutex locked */ -static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) +static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)  { -	struct b43_wldev *up_dev; +	struct b43_wldev *up_dev = NULL;  	struct b43_wldev *down_dev; +	struct b43_wldev *d;  	int err; -	bool gmode = 0; +	bool gmode;  	int prev_status; -	err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode); -	if (err) { -		b43err(wl, "Could not find a device for %s-PHY mode\n", -		       phymode_to_string(new_mode)); -		return err; +	/* Find a device and PHY which supports the band. */ +	list_for_each_entry(d, &wl->devlist, list) { +		switch (chan->band) { +		case IEEE80211_BAND_5GHZ: +			if (d->phy.supports_5ghz) { +				up_dev = d; +				gmode = 0; +			} +			break; +		case IEEE80211_BAND_2GHZ: +			if (d->phy.supports_2ghz) { +				up_dev = d; +				gmode = 1; +			} +			break; +		default: +			B43_WARN_ON(1); +			return -EINVAL; +		} +		if (up_dev) +			break; +	} +	if (!up_dev) { +		b43err(wl, "Could not find a device for %s-GHz band operation\n", +		       band_to_string(chan->band)); +		return -ENODEV;  	}  	if ((up_dev == wl->current_dev) &&  	    (!!wl->current_dev->phy.gmode == !!gmode)) {  		/* This device is already running. */  		return 0;  	} -	b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n", -	       phymode_to_string(new_mode)); +	b43dbg(wl, "Switching to %s-GHz band\n", +	       band_to_string(chan->band));  	down_dev = wl->current_dev;  	prev_status = b43_status(down_dev); @@ -2755,8 +3270,8 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)  		err = b43_wireless_core_init(up_dev);  		if (err) {  			b43err(wl, "Fatal: Could not initialize device for " -			       "newly selected %s-PHY mode\n", -			       phymode_to_string(new_mode)); +			       "selected %s-GHz band\n", +			       band_to_string(chan->band));  			goto init_failure;  		}  	} @@ -2764,8 +3279,8 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)  		err = b43_wireless_core_start(up_dev);  		if (err) {  			b43err(wl, "Fatal: Coult not start device for " -			       "newly selected %s-PHY mode\n", -			       phymode_to_string(new_mode)); +			       "selected %s-GHz band\n", +			       band_to_string(chan->band));  			b43_wireless_core_exit(up_dev);  			goto init_failure;  		} @@ -2775,83 +3290,26 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)  	wl->current_dev = up_dev;  	return 0; -      init_failure: +init_failure:  	/* Whoops, failed to init the new core. No core is operating now. */  	wl->current_dev = NULL;  	return err;  } -/* Check if the use of the antenna that ieee80211 told us to - * use is possible. This will fall back to DEFAULT. - * "antenna_nr" is the antenna identifier we got from ieee80211. */ -u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, -				  u8 antenna_nr) -{ -	u8 antenna_mask; - -	if (antenna_nr == 0) { -		/* Zero means "use default antenna". That's always OK. */ -		return 0; -	} - -	/* Get the mask of available antennas. */ -	if (dev->phy.gmode) -		antenna_mask = dev->dev->bus->sprom.ant_available_bg; -	else -		antenna_mask = dev->dev->bus->sprom.ant_available_a; - -	if (!(antenna_mask & (1 << (antenna_nr - 1)))) { -		/* This antenna is not available. Fall back to default. */ -		return 0; -	} - -	return antenna_nr; -} - -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ -	antenna = b43_ieee80211_antenna_sanitize(dev, antenna); -	switch (antenna) { -	case 0:		/* default/diversity */ -		return B43_ANTENNA_DEFAULT; -	case 1:		/* Antenna 0 */ -		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; -	} -} -  static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)  {  	struct b43_wl *wl = hw_to_b43_wl(hw);  	struct b43_wldev *dev;  	struct b43_phy *phy;  	unsigned long flags; -	unsigned int new_phymode = 0xFFFF;  	int antenna;  	int err = 0;  	u32 savedirqs;  	mutex_lock(&wl->mutex); -	/* Switch the PHY mode (if necessary). */ -	switch (conf->channel->band) { -	case IEEE80211_BAND_5GHZ: -		new_phymode = B43_PHYMODE_A; -		break; -	case IEEE80211_BAND_2GHZ: -		new_phymode = B43_PHYMODE_G; -		break; -	default: -		B43_WARN_ON(1); -	} -	err = b43_switch_phymode(wl, new_phymode); +	/* Switch the band (if necessary). This might change the active core. */ +	err = b43_switch_band(wl, conf->channel);  	if (err)  		goto out_unlock_mutex;  	dev = wl->current_dev; @@ -2952,6 +3410,13 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,  	if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)  		goto out_unlock; +	if (dev->fw.pcm_request_failed) { +		/* We don't have firmware for the crypto engine. +		 * Must use software-crypto. */ +		err = -EOPNOTSUPP; +		goto out_unlock; +	} +  	err = -EINVAL;  	switch (key->alg) {  	case ALG_WEP: @@ -3114,16 +3579,17 @@ static void b43_wireless_core_stop(struct b43_wldev *dev)  	spin_unlock_irqrestore(&wl->irq_lock, flags);  	b43_synchronize_irq(dev); +	write_lock_irqsave(&wl->tx_lock, flags);  	b43_set_status(dev, B43_STAT_INITIALIZED); +	write_unlock_irqrestore(&wl->tx_lock, flags); +	b43_pio_stop(dev);  	mutex_unlock(&wl->mutex);  	/* Must unlock as it would otherwise deadlock. No races here.  	 * Cancel the possibly running self-rearming periodic work. */  	cancel_delayed_work_sync(&dev->periodic_work);  	mutex_lock(&wl->mutex); -	ieee80211_stop_queues(wl->hw);	//FIXME this could cause a deadlock, as mac80211 seems buggy. -  	b43_mac_suspend(dev);  	free_irq(dev->dev->irq, dev);  	b43dbg(wl, "Wireless interface stopped\n"); @@ -3150,7 +3616,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev)  	/* Start data flow (TX/RX). */  	b43_mac_enable(dev);  	b43_interrupt_enable(dev, dev->irq_savedstate); -	ieee80211_start_queues(dev->wl->hw);  	/* Start maintainance work */  	b43_periodic_tasks_setup(dev); @@ -3291,8 +3756,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,  	lo = phy->lo_control;  	if (lo) {  		memset(lo, 0, sizeof(*(phy->lo_control))); -		lo->rebuild = 1;  		lo->tx_bias = 0xFF; +		INIT_LIST_HEAD(&lo->calib_list);  	}  	phy->max_lb_gain = 0;  	phy->trsw_rx_gain = 0; @@ -3347,8 +3812,10 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)  static void b43_bluetooth_coext_enable(struct b43_wldev *dev)  {  	struct ssb_sprom *sprom = &dev->dev->bus->sprom; -	u32 hf; +	u64 hf; +	if (!modparam_btcoex) +		return;  	if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))  		return;  	if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode) @@ -3360,11 +3827,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)  	else  		hf |= B43_HF_BTCOEX;  	b43_hf_write(dev, hf); -	//TODO  }  static void b43_bluetooth_coext_disable(struct b43_wldev *dev) -{				//TODO +{ +	if (!modparam_btcoex) +		return; +	//TODO  }  static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) @@ -3410,6 +3879,41 @@ static void b43_set_retry_limits(struct b43_wldev *dev,  			long_retry);  } +static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) +{ +	u16 pu_delay; + +	/* The time value is in microseconds. */ +	if (dev->phy.type == B43_PHYTYPE_A) +		pu_delay = 3700; +	else +		pu_delay = 1050; +	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS) || idle) +		pu_delay = 500; +	if ((dev->phy.radio_ver == 0x2050) && (dev->phy.radio_rev == 8)) +		pu_delay = max(pu_delay, (u16)2400); + +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SPUWKUP, pu_delay); +} + +/* Set the TSF CFP pre-TargetBeaconTransmissionTime. */ +static void b43_set_pretbtt(struct b43_wldev *dev) +{ +	u16 pretbtt; + +	/* The time value is in microseconds. */ +	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) { +		pretbtt = 2; +	} else { +		if (dev->phy.type == B43_PHYTYPE_A) +			pretbtt = 120; +		else +			pretbtt = 250; +	} +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRETBTT, pretbtt); +	b43_write16(dev, B43_MMIO_TSF_CFP_PRETBTT, pretbtt); +} +  /* Shutdown a wireless core */  /* Locking: wl->mutex */  static void b43_wireless_core_exit(struct b43_wldev *dev) @@ -3428,9 +3932,12 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)  	macctl |= B43_MACCTL_PSM_JMP0;  	b43_write32(dev, B43_MMIO_MACCTL, macctl); -	b43_leds_exit(dev); -	b43_rng_exit(dev->wl); +	if (!dev->suspend_in_progress) { +		b43_leds_exit(dev); +		b43_rng_exit(dev->wl); +	}  	b43_dma_free(dev); +	b43_pio_free(dev);  	b43_chip_exit(dev);  	b43_radio_turn_off(dev, 1);  	b43_switch_analog(dev, 0); @@ -3455,7 +3962,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)  	struct ssb_sprom *sprom = &bus->sprom;  	struct b43_phy *phy = &dev->phy;  	int err; -	u32 hf, tmp; +	u64 hf; +	u32 tmp;  	B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); @@ -3518,6 +4026,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)  	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);  	b43_rate_memory_init(dev); +	b43_set_phytxctl_defaults(dev);  	/* Minimum Contention Window */  	if (phy->type == B43_PHYTYPE_B) { @@ -3528,28 +4037,29 @@ static int b43_wireless_core_init(struct b43_wldev *dev)  	/* Maximum Contention Window */  	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); -	err = b43_dma_init(dev); +	if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { +		dev->__using_pio_transfers = 1; +		err = b43_pio_init(dev); +	} else { +		dev->__using_pio_transfers = 0; +		err = b43_dma_init(dev); +	}  	if (err)  		goto err_chip_exit;  	b43_qos_init(dev); - -//FIXME -#if 1 -	b43_write16(dev, 0x0612, 0x0050); -	b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050); -	b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4); -#endif - +	b43_set_synth_pu_delay(dev, 1);  	b43_bluetooth_coext_enable(dev);  	ssb_bus_powerup(bus, 1);	/* Enable dynamic PCTL */  	b43_upload_card_macaddress(dev);  	b43_security_init(dev); -	b43_rng_init(wl); +	if (!dev->suspend_in_progress) +		b43_rng_init(wl);  	b43_set_status(dev, B43_STAT_INITIALIZED); -	b43_leds_init(dev); +	if (!dev->suspend_in_progress) +		b43_leds_init(dev);  out:  	return err; @@ -3597,6 +4107,8 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,  	spin_lock_irqsave(&wl->irq_lock, flags);  	b43_adjust_opmode(dev); +	b43_set_pretbtt(dev); +	b43_set_synth_pu_delay(dev, 0);  	b43_upload_card_macaddress(dev);  	spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -3648,6 +4160,7 @@ static int b43_op_start(struct ieee80211_hw *hw)  	memset(wl->mac_addr, 0, ETH_ALEN);  	wl->filter_flags = 0;  	wl->radiotap_enabled = 0; +	b43_qos_clear(wl);  	/* First register RFkill.  	 * LEDs that are registered later depend on it. */ @@ -3689,6 +4202,8 @@ static void b43_op_stop(struct ieee80211_hw *hw)  	struct b43_wldev *dev = wl->current_dev;  	b43_rfkill_exit(dev); +	cancel_work_sync(&(wl->qos_update_work)); +	cancel_work_sync(&(wl->beacon_update_trigger));  	mutex_lock(&wl->mutex);  	if (b43_status(dev) >= B43_STAT_STARTED) @@ -3727,7 +4242,7 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)  	 * the TIM field, but that would probably require resizing and  	 * moving of data within the beacon template.  	 * Simply request a new beacon and let mac80211 do the hard work. */ -	beacon = ieee80211_beacon_get(hw, wl->vif, NULL); +	beacon = ieee80211_beacon_get(hw, wl->vif);  	if (unlikely(!beacon))  		return -ENOMEM;  	spin_lock_irqsave(&wl->irq_lock, flags); @@ -3738,8 +4253,7 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)  }  static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, -				     struct sk_buff *beacon, -				     struct ieee80211_tx_control *ctl) +				     struct sk_buff *beacon)  {  	struct b43_wl *wl = hw_to_b43_wl(hw);  	unsigned long flags; @@ -3751,6 +4265,16 @@ static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,  	return 0;  } +static void b43_op_sta_notify(struct ieee80211_hw *hw, +			      struct ieee80211_vif *vif, +			      enum sta_notify_cmd notify_cmd, +			      const u8 *addr) +{ +	struct b43_wl *wl = hw_to_b43_wl(hw); + +	B43_WARN_ON(!vif || wl->vif != vif); +} +  static const struct ieee80211_ops b43_hw_ops = {  	.tx			= b43_op_tx,  	.conf_tx		= b43_op_conf_tx, @@ -3767,6 +4291,7 @@ static const struct ieee80211_ops b43_hw_ops = {  	.set_retry_limit	= b43_op_set_retry_limit,  	.set_tim		= b43_op_beacon_set_tim,  	.beacon_update		= b43_op_ibss_beacon_update, +	.sta_notify		= b43_op_sta_notify,  };  /* Hard-reset the chip. Do not call this directly. @@ -3810,21 +4335,23 @@ static void b43_chip_reset(struct work_struct *work)  		b43info(wl, "Controller restarted\n");  } -static int b43_setup_modes(struct b43_wldev *dev, +static int b43_setup_bands(struct b43_wldev *dev,  			   bool have_2ghz_phy, bool have_5ghz_phy)  {  	struct ieee80211_hw *hw = dev->wl->hw; -	struct b43_phy *phy = &dev->phy; -	/* XXX: This function will go away soon, when mac80211 -	 *      band stuff is rewritten. So this is just a hack. -	 *      For now we always claim GPHY mode, as there is no -	 *      support for NPHY and APHY in the device, yet. -	 *      This assumption is OK, as any B, N or A PHY will already -	 *      have died a horrible sanity check death earlier. */ +	if (have_2ghz_phy) +		hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; +	if (dev->phy.type == B43_PHYTYPE_N) { +		if (have_5ghz_phy) +			hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_nphy; +	} else { +		if (have_5ghz_phy) +			hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &b43_band_5GHz_aphy; +	} -	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; -	phy->possible_phymodes |= B43_PHYMODE_G; +	dev->phy.supports_2ghz = have_2ghz_phy; +	dev->phy.supports_5ghz = have_5ghz_phy;  	return 0;  } @@ -3899,6 +4426,14 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)  		err = -EOPNOTSUPP;  		goto err_powerdown;  	} +	if (1 /* disable A-PHY */) { +		/* FIXME: For now we disable the A-PHY on multi-PHY devices. */ +		if (dev->phy.type != B43_PHYTYPE_N) { +			have_2ghz_phy = 1; +			have_5ghz_phy = 0; +		} +	} +  	dev->phy.gmode = have_2ghz_phy;  	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;  	b43_wireless_core_reset(dev, tmp); @@ -3906,7 +4441,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)  	err = b43_validate_chipaccess(dev);  	if (err)  		goto err_powerdown; -	err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy); +	err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);  	if (err)  		goto err_powerdown; @@ -3996,8 +4531,16 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)  	return err;  } +#define IS_PDEV(pdev, _vendor, _device, _subvendor, _subdevice)		( \ +	(pdev->vendor == PCI_VENDOR_ID_##_vendor) &&			\ +	(pdev->device == _device) &&					\ +	(pdev->subsystem_vendor == PCI_VENDOR_ID_##_subvendor) &&	\ +	(pdev->subsystem_device == _subdevice)				) +  static void b43_sprom_fixup(struct ssb_bus *bus)  { +	struct pci_dev *pdev; +  	/* boardflags workarounds */  	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&  	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) @@ -4005,6 +4548,13 @@ static void b43_sprom_fixup(struct ssb_bus *bus)  	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&  	    bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)  		bus->sprom.boardflags_lo |= B43_BFL_PACTRL; +	if (bus->bustype == SSB_BUSTYPE_PCI) { +		pdev = bus->host_pci; +		if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) || +		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) || +		    IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013)) +			bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST; +	}  }  static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) @@ -4032,11 +4582,11 @@ static int b43_wireless_init(struct ssb_device *dev)  	/* fill hw info */  	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | -		    IEEE80211_HW_RX_INCLUDES_FCS; -	hw->max_signal = 100; -	hw->max_rssi = -110; -	hw->max_noise = -110; -	hw->queues = 1;		/* FIXME: hardware has more queues */ +		    IEEE80211_HW_RX_INCLUDES_FCS | +		    IEEE80211_HW_SIGNAL_DBM | +		    IEEE80211_HW_NOISE_DBM; + +	hw->queues = b43_modparam_qos ? 4 : 1;  	SET_IEEE80211_DEV(hw, dev->dev);  	if (is_valid_ether_addr(sprom->et1mac))  		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); @@ -4048,10 +4598,13 @@ static int b43_wireless_init(struct ssb_device *dev)  	memset(wl, 0, sizeof(*wl));  	wl->hw = hw;  	spin_lock_init(&wl->irq_lock); +	rwlock_init(&wl->tx_lock);  	spin_lock_init(&wl->leds_lock);  	spin_lock_init(&wl->shm_lock);  	mutex_init(&wl->mutex);  	INIT_LIST_HEAD(&wl->devlist); +	INIT_WORK(&wl->qos_update_work, b43_qos_update_work); +	INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);  	ssb_set_devtypedata(dev, wl);  	b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); @@ -4136,6 +4689,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state)  	b43dbg(wl, "Suspending...\n");  	mutex_lock(&wl->mutex); +	wldev->suspend_in_progress = true;  	wldev->suspend_init_status = b43_status(wldev);  	if (wldev->suspend_init_status >= B43_STAT_STARTED)  		b43_wireless_core_stop(wldev); @@ -4167,15 +4721,17 @@ static int b43_resume(struct ssb_device *dev)  	if (wldev->suspend_init_status >= B43_STAT_STARTED) {  		err = b43_wireless_core_start(wldev);  		if (err) { +			b43_leds_exit(wldev); +			b43_rng_exit(wldev->wl);  			b43_wireless_core_exit(wldev);  			b43err(wl, "Resume failed at core start\n");  			goto out;  		}  	} -	mutex_unlock(&wl->mutex); -  	b43dbg(wl, "Device resumed.\n"); -      out: + out: +	wldev->suspend_in_progress = false; +	mutex_unlock(&wl->mutex);  	return err;  } @@ -4193,6 +4749,33 @@ static struct ssb_driver b43_ssb_driver = {  	.resume		= b43_resume,  }; +static void b43_print_driverinfo(void) +{ +	const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", +		   *feat_leds = "", *feat_rfkill = ""; + +#ifdef CONFIG_B43_PCI_AUTOSELECT +	feat_pci = "P"; +#endif +#ifdef CONFIG_B43_PCMCIA +	feat_pcmcia = "M"; +#endif +#ifdef CONFIG_B43_NPHY +	feat_nphy = "N"; +#endif +#ifdef CONFIG_B43_LEDS +	feat_leds = "L"; +#endif +#ifdef CONFIG_B43_RFKILL +	feat_rfkill = "R"; +#endif +	printk(KERN_INFO "Broadcom 43xx driver loaded " +	       "[ Features: %s%s%s%s%s, Firmware-ID: " +	       B43_SUPPORTED_FIRMWARE_ID " ]\n", +	       feat_pci, feat_pcmcia, feat_nphy, +	       feat_leds, feat_rfkill); +} +  static int __init b43_init(void)  {  	int err; @@ -4204,6 +4787,7 @@ static int __init b43_init(void)  	err = ssb_driver_register(&b43_ssb_driver);  	if (err)  		goto err_pcmcia_exit; +	b43_print_driverinfo();  	return err; diff --git a/package/b43/src/main.h b/package/b43/src/main.h index 2d52d9de9..dad23c42b 100644 --- a/package/b43/src/main.h +++ b/package/b43/src/main.h @@ -38,6 +38,10 @@  /* Magic helper macro to pad structures. Ignore those above. It's magic. */  #define PAD_BYTES(nr_bytes)		P4D_BYTES( __LINE__ , (nr_bytes)) + +extern int b43_modparam_qos; + +  /* Lightweight function to convert a frequency (in Mhz) to a channel number. */  static inline u8 b43_freq_to_channel_5ghz(int freq)  { @@ -95,16 +99,13 @@ u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);  void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);  void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); -u32 b43_hf_read(struct b43_wldev *dev); -void b43_hf_write(struct b43_wldev *dev, u32 value); +u64 b43_hf_read(struct b43_wldev *dev); +void b43_hf_write(struct b43_wldev *dev, u64 value);  void b43_dummy_transmission(struct b43_wldev *dev);  void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags); -void b43_mac_suspend(struct b43_wldev *dev); -void b43_mac_enable(struct b43_wldev *dev); -  void b43_controller_restart(struct b43_wldev *dev, const char *reason);  #define B43_PS_ENABLED	(1 << 0)	/* Force enable hardware power saving */ @@ -113,4 +114,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason);  #define B43_PS_ASLEEP	(1 << 3)	/* Force device asleep */  void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); +  #endif /* B43_MAIN_H_ */ diff --git a/package/b43/src/nphy.c b/package/b43/src/nphy.c index 705131ef4..644eed993 100644 --- a/package/b43/src/nphy.c +++ b/package/b43/src/nphy.c @@ -29,8 +29,6 @@  #include "nphy.h"  #include "tables_nphy.h" -#include <linux/delay.h> -  void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)  {//TODO @@ -240,7 +238,6 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)  	b43_phy_set(dev, B43_NPHY_IQFLIP,  		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); -	//FIXME the following condition is different in the specs.  	if (1 /* FIXME band is 2.4GHz */) {  		b43_phy_set(dev, B43_NPHY_CLASSCTL,  			    B43_NPHY_CLASSCTL_CCKEN); diff --git a/package/b43/src/nphy.h b/package/b43/src/nphy.h index 5d95118b8..faf46b9cb 100644 --- a/package/b43/src/nphy.h +++ b/package/b43/src/nphy.h @@ -919,6 +919,10 @@  struct b43_wldev; + +#ifdef CONFIG_B43_NPHY +/* N-PHY support enabled */ +  int b43_phy_initn(struct b43_wldev *dev);  void b43_nphy_radio_turn_on(struct b43_wldev *dev); @@ -929,4 +933,40 @@ int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);  void b43_nphy_xmitpower(struct b43_wldev *dev);  void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); + +#else /* CONFIG_B43_NPHY */ +/* N-PHY support disabled */ + + +static inline +int b43_phy_initn(struct b43_wldev *dev) +{ +	return -EOPNOTSUPP; +} + +static inline +void b43_nphy_radio_turn_on(struct b43_wldev *dev) +{ +} +static inline +void b43_nphy_radio_turn_off(struct b43_wldev *dev) +{ +} + +static inline +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +{ +	return -ENOSYS; +} + +static inline +void b43_nphy_xmitpower(struct b43_wldev *dev) +{ +} +static inline +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) +{ +} + +#endif /* CONFIG_B43_NPHY */  #endif /* B43_NPHY_H_ */ diff --git a/package/b43/src/pcmcia.c b/package/b43/src/pcmcia.c index b79a6bd53..b8aa16307 100644 --- a/package/b43/src/pcmcia.c +++ b/package/b43/src/pcmcia.c @@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);  #ifdef CONFIG_PM  static int b43_pcmcia_suspend(struct pcmcia_device *dev)  { -	//TODO -	return 0; +	struct ssb_bus *ssb = dev->priv; + +	return ssb_bus_suspend(ssb);  }  static int b43_pcmcia_resume(struct pcmcia_device *dev)  { -	//TODO -	return 0; +	struct ssb_bus *ssb = dev->priv; + +	return ssb_bus_resume(ssb);  }  #else /* CONFIG_PM */  # define b43_pcmcia_suspend		NULL @@ -91,6 +93,8 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)  	dev->conf.ConfigBase = parse.config.base;  	dev->conf.Present = parse.config.rmask[0]; +	dev->conf.Attributes = CONF_ENABLE_IRQ; +	dev->conf.IntType = INT_MEMORY_AND_IO;  	dev->io.BasePort2 = 0;  	dev->io.NumPorts2 = 0; @@ -112,8 +116,8 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)  	if (res != CS_SUCCESS)  		goto err_disable; -	dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED; -	dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID; +	dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; +	dev->irq.IRQInfo1 = IRQ_LEVEL_ID;  	dev->irq.Handler = NULL; /* The handler is registered later. */  	dev->irq.Instance = NULL;  	res = pcmcia_request_irq(dev, &dev->irq); diff --git a/package/b43/src/phy.c b/package/b43/src/phy.c index 71507b260..305d4cd6f 100644 --- a/package/b43/src/phy.c +++ b/package/b43/src/phy.c @@ -28,6 +28,7 @@  #include <linux/delay.h>  #include <linux/io.h>  #include <linux/types.h> +#include <linux/bitrev.h>  #include "b43.h"  #include "phy.h" @@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = {  	72, 84,  }; +#define bitrev4(tmp) (bitrev8(tmp) >> 4)  static void b43_phy_initg(struct b43_wldev *dev); -/* Reverse the bits of a 4bit value. - * Example:  1101 is flipped 1011 - */ -static u16 flip_4bit(u16 value) -{ -	u16 flipped = 0x0000; - -	B43_WARN_ON(value & ~0x000F); - -	flipped |= (value & 0x0001) << 3; -	flipped |= (value & 0x0002) << 1; -	flipped |= (value & 0x0004) >> 1; -	flipped |= (value & 0x0008) >> 3; - -	return flipped; -} -  static void generate_rfatt_list(struct b43_wldev *dev,  				struct b43_rfatt_list *list)  { @@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,  		{.att = 9,.with_padmix = 1,},  	}; -	if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || -	    (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { +	if (!b43_has_hardware_pctl(phy)) {  		/* Software pctl */  		list->list = rfatt_0;  		list->len = ARRAY_SIZE(rfatt_0); @@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,  		/* Hardware pctl */  		list->list = rfatt_1;  		list->len = ARRAY_SIZE(rfatt_1); -		list->min_val = 2; +		list->min_val = 0;  		list->max_val = 14;  		return;  	} @@ -346,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev,  	/* Save the values for later */  	phy->tx_control = tx_control;  	memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); +	phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);  	memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));  	if (b43_debug(dev, B43_DBG_XMITPOWER)) { @@ -559,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)  	u16 tmp;  	u8 rf, bb; -	if (!lo->lo_measured) { -		b43_phy_write(dev, 0x3FF, 0); -		return; -	} -  	for (rf = 0; rf < lo->rfatt_list.len; rf++) {  		for (bb = 0; bb < lo->bbatt_list.len; bb++) {  			if (nr_written >= 0x40) @@ -581,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)  	}  } -/* GPHY_DC_Lookup_Table */ -void b43_gphy_dc_lt_init(struct b43_wldev *dev) -{ -	struct b43_phy *phy = &dev->phy; -	struct b43_txpower_lo_control *lo = phy->lo_control; -	struct b43_loctl *loctl0; -	struct b43_loctl *loctl1; -	int i; -	int rf_offset, bb_offset; -	u16 tmp; - -	for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { -		rf_offset = i / lo->rfatt_list.len; -		bb_offset = i % lo->rfatt_list.len; - -		loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], -					  &lo->bbatt_list.list[bb_offset]); -		if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { -			rf_offset = (i + 1) / lo->rfatt_list.len; -			bb_offset = (i + 1) % lo->rfatt_list.len; - -			loctl1 = -			    b43_get_lo_g_ctl(dev, -					     &lo->rfatt_list.list[rf_offset], -					     &lo->bbatt_list.list[bb_offset]); -		} else -			loctl1 = loctl0; - -		tmp = ((u16) loctl0->q & 0xF); -		tmp |= ((u16) loctl0->i & 0xF) << 4; -		tmp |= ((u16) loctl1->q & 0xF) << 8; -		tmp |= ((u16) loctl1->i & 0xF) << 12;	//FIXME? -		b43_phy_write(dev, 0x3A0 + (i / 2), tmp); -	} -} -  static void hardware_pctl_init_aphy(struct b43_wldev *dev)  {  	//TODO @@ -643,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev)  	b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)  		      & 0xFFBF); -	b43_gphy_dc_lt_init(dev); +	b43_gphy_dc_lt_init(dev, 1);  }  /* HardwarePowerControl init for A and G PHY */ @@ -860,7 +804,7 @@ static void b43_phy_ww(struct b43_wldev *dev)  	b43_phy_write(dev, B43_PHY_OFDM(0xBB),  		(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);  	b43_phy_write(dev, B43_PHY_OFDM61, -		(b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120); +		(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);  	b43_phy_write(dev, B43_PHY_OFDM(0x13),  		(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);  	b43_phy_write(dev, B43_PHY_OFDM(0x14), @@ -931,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev)  	}  } -static void b43_phy_initb2(struct b43_wldev *dev) -{ -	struct b43_phy *phy = &dev->phy; -	u16 offset, val; - -	b43_write16(dev, 0x03EC, 0x3F22); -	b43_phy_write(dev, 0x0020, 0x301C); -	b43_phy_write(dev, 0x0026, 0x0000); -	b43_phy_write(dev, 0x0030, 0x00C6); -	b43_phy_write(dev, 0x0088, 0x3E00); -	val = 0x3C3D; -	for (offset = 0x0089; offset < 0x00A7; offset++) { -		b43_phy_write(dev, offset, val); -		val -= 0x0202; -	} -	b43_phy_write(dev, 0x03E4, 0x3000); -	b43_radio_selectchannel(dev, phy->channel, 0); -	if (phy->radio_ver != 0x2050) { -		b43_radio_write16(dev, 0x0075, 0x0080); -		b43_radio_write16(dev, 0x0079, 0x0081); -	} -	b43_radio_write16(dev, 0x0050, 0x0020); -	b43_radio_write16(dev, 0x0050, 0x0023); -	if (phy->radio_ver == 0x2050) { -		b43_radio_write16(dev, 0x0050, 0x0020); -		b43_radio_write16(dev, 0x005A, 0x0070); -		b43_radio_write16(dev, 0x005B, 0x007B); -		b43_radio_write16(dev, 0x005C, 0x00B0); -		b43_radio_write16(dev, 0x007A, 0x000F); -		b43_phy_write(dev, 0x0038, 0x0677); -		b43_radio_init2050(dev); -	} -	b43_phy_write(dev, 0x0014, 0x0080); -	b43_phy_write(dev, 0x0032, 0x00CA); -	b43_phy_write(dev, 0x0032, 0x00CC); -	b43_phy_write(dev, 0x0035, 0x07C2); -	b43_lo_b_measure(dev); -	b43_phy_write(dev, 0x0026, 0xCC00); -	if (phy->radio_ver != 0x2050) -		b43_phy_write(dev, 0x0026, 0xCE00); -	b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); -	b43_phy_write(dev, 0x002A, 0x88A3); -	if (phy->radio_ver != 0x2050) -		b43_phy_write(dev, 0x002A, 0x88C2); -	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); -	b43_phy_init_pctl(dev); -} - -static void b43_phy_initb4(struct b43_wldev *dev) -{ -	struct b43_phy *phy = &dev->phy; -	u16 offset, val; - -	b43_write16(dev, 0x03EC, 0x3F22); -	b43_phy_write(dev, 0x0020, 0x301C); -	b43_phy_write(dev, 0x0026, 0x0000); -	b43_phy_write(dev, 0x0030, 0x00C6); -	b43_phy_write(dev, 0x0088, 0x3E00); -	val = 0x3C3D; -	for (offset = 0x0089; offset < 0x00A7; offset++) { -		b43_phy_write(dev, offset, val); -		val -= 0x0202; -	} -	b43_phy_write(dev, 0x03E4, 0x3000); -	b43_radio_selectchannel(dev, phy->channel, 0); -	if (phy->radio_ver != 0x2050) { -		b43_radio_write16(dev, 0x0075, 0x0080); -		b43_radio_write16(dev, 0x0079, 0x0081); -	} -	b43_radio_write16(dev, 0x0050, 0x0020); -	b43_radio_write16(dev, 0x0050, 0x0023); -	if (phy->radio_ver == 0x2050) { -		b43_radio_write16(dev, 0x0050, 0x0020); -		b43_radio_write16(dev, 0x005A, 0x0070); -		b43_radio_write16(dev, 0x005B, 0x007B); -		b43_radio_write16(dev, 0x005C, 0x00B0); -		b43_radio_write16(dev, 0x007A, 0x000F); -		b43_phy_write(dev, 0x0038, 0x0677); -		b43_radio_init2050(dev); -	} -	b43_phy_write(dev, 0x0014, 0x0080); -	b43_phy_write(dev, 0x0032, 0x00CA); -	if (phy->radio_ver == 0x2050) -		b43_phy_write(dev, 0x0032, 0x00E0); -	b43_phy_write(dev, 0x0035, 0x07C2); - -	b43_lo_b_measure(dev); - -	b43_phy_write(dev, 0x0026, 0xCC00); -	if (phy->radio_ver == 0x2050) -		b43_phy_write(dev, 0x0026, 0xCE00); -	b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); -	b43_phy_write(dev, 0x002A, 0x88A3); -	if (phy->radio_ver == 0x2050) -		b43_phy_write(dev, 0x002A, 0x88C2); -	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); -	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { -		b43_calc_nrssi_slope(dev); -		b43_calc_nrssi_threshold(dev); -	} -	b43_phy_init_pctl(dev); -} -  static void b43_phy_initb5(struct b43_wldev *dev)  {  	struct ssb_bus *bus = dev->dev->bus; @@ -1259,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev)  		b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)  			      | 0x0004);  	} -	if (phy->type == B43_PHYTYPE_B) { -		b43_write16(dev, 0x03E6, 0x8140); -		b43_phy_write(dev, 0x0016, 0x0410); -		b43_phy_write(dev, 0x0017, 0x0820); -		b43_phy_write(dev, 0x0062, 0x0007); -		b43_radio_init2050(dev); -		b43_lo_g_measure(dev); -		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { -			b43_calc_nrssi_slope(dev); -			b43_calc_nrssi_threshold(dev); -		} -		b43_phy_init_pctl(dev); -	} else if (phy->type == B43_PHYTYPE_G) +	if (phy->type == B43_PHYTYPE_B) +		B43_WARN_ON(1); +	else if (phy->type == B43_PHYTYPE_G)  		b43_write16(dev, 0x03E6, 0x0);  } @@ -1534,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev)  		else  			b43_radio_write16(dev, 0x0078, phy->initval);  	} -	if (phy->lo_control->tx_bias == 0xFF) { -		b43_lo_g_measure(dev); +	b43_lo_g_init(dev); +	if (has_tx_magnification(phy)) { +		b43_radio_write16(dev, 0x52, +				  (b43_radio_read16(dev, 0x52) & 0xFF00) +				  | phy->lo_control->tx_bias | phy-> +				  lo_control->tx_magn);  	} else { -		if (has_tx_magnification(phy)) { -			b43_radio_write16(dev, 0x52, -					  (b43_radio_read16(dev, 0x52) & 0xFF00) -					  | phy->lo_control->tx_bias | phy-> -					  lo_control->tx_magn); -		} else { -			b43_radio_write16(dev, 0x52, -					  (b43_radio_read16(dev, 0x52) & 0xFFF0) -					  | phy->lo_control->tx_bias); -		} -		if (phy->rev >= 6) { -			b43_phy_write(dev, B43_PHY_CCK(0x36), -				      (b43_phy_read(dev, B43_PHY_CCK(0x36)) -				       & 0x0FFF) | (phy->lo_control-> -						    tx_bias << 12)); -		} -		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) -			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); -		else -			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); -		if (phy->rev < 2) -			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); -		else -			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); +		b43_radio_write16(dev, 0x52, +				  (b43_radio_read16(dev, 0x52) & 0xFFF0) +				  | phy->lo_control->tx_bias);  	} +	if (phy->rev >= 6) { +		b43_phy_write(dev, B43_PHY_CCK(0x36), +			      (b43_phy_read(dev, B43_PHY_CCK(0x36)) +			       & 0x0FFF) | (phy->lo_control-> +					    tx_bias << 12)); +	} +	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) +		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); +	else +		b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); +	if (phy->rev < 2) +		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); +	else +		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);  	if (phy->gmode || phy->rev >= 2) {  		b43_lo_g_adjust(dev);  		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); @@ -1572,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev)  		 * the value 0x7FFFFFFF here. I think that is some weird  		 * compiler optimization in the original driver.  		 * Essentially, what we do here is resetting all NRSSI LT -		 * entries to -32 (see the limit_value() in nrssi_hw_update()) +		 * entries to -32 (see the clamp_val() in nrssi_hw_update())  		 */  		b43_nrssi_hw_update(dev, 0xFFFF);	//FIXME?  		b43_calc_nrssi_threshold(dev); @@ -1634,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)  	switch (phy->type) {  	case B43_PHYTYPE_A:  		tmp += 0x80; -		tmp = limit_value(tmp, 0x00, 0xFF); +		tmp = clamp_val(tmp, 0x00, 0xFF);  		dbm = phy->tssi2dbm[tmp];  		//TODO: There's a FIXME on the specs  		break;  	case B43_PHYTYPE_B:  	case B43_PHYTYPE_G: -		tmp = limit_value(tmp, 0x00, 0x3F); +		tmp = clamp_val(tmp, 0x00, 0x3F);  		dbm = phy->tssi2dbm[tmp];  		break;  	default: @@ -1699,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev,  		break;  	} -	*_rfatt = limit_value(rfatt, rf_min, rf_max); -	*_bbatt = limit_value(bbatt, bb_min, bb_max); +	*_rfatt = clamp_val(rfatt, rf_min, rf_max); +	*_bbatt = clamp_val(bbatt, bb_min, bb_max);  }  /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ @@ -1795,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)  			/* Get desired power (in Q5.2) */  			desired_pwr = INT_TO_Q52(phy->power_level);  			/* And limit it. max_pwr already is Q5.2 */ -			desired_pwr = limit_value(desired_pwr, 0, max_pwr); +			desired_pwr = clamp_val(desired_pwr, 0, max_pwr);  			if (b43_debug(dev, B43_DBG_XMITPOWER)) {  				b43dbg(dev->wl,  				       "Current TX power output: " Q52_FMT @@ -1821,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev)  			bbatt_delta -= 4 * rfatt_delta;  			/* So do we finally need to adjust something? */ -			if ((rfatt_delta == 0) && (bbatt_delta == 0)) { -				b43_lo_g_ctl_mark_cur_used(dev); +			if ((rfatt_delta == 0) && (bbatt_delta == 0))  				return; -			}  			/* Calculate the new attenuation values. */  			bbatt = phy->bbatt.att; @@ -1870,7 +1696,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)  			b43_radio_lock(dev);  			b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,  					  phy->tx_control); -			b43_lo_g_ctl_mark_cur_used(dev);  			b43_radio_unlock(dev);  			b43_phy_unlock(dev);  			break; @@ -1908,7 +1733,7 @@ static inline  		f = q;  		i++;  	} while (delta >= 2); -	entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); +	entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);  	return 0;  } @@ -2007,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev)  		else  			unsupported = 1;  		break; -	case B43_PHYTYPE_B: -		switch (phy->rev) { -		case 2: -			b43_phy_initb2(dev); -			break; -		case 4: -			b43_phy_initb4(dev); -			break; -		case 5: -			b43_phy_initb5(dev); -			break; -		case 6: -			b43_phy_initb6(dev); -			break; -		default: -			unsupported = 1; -		} -		break;  	case B43_PHYTYPE_G:  		b43_phy_initg(dev);  		break; @@ -2043,7 +1850,7 @@ int b43_phy_init(struct b43_wldev *dev)  void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)  {  	struct b43_phy *phy = &dev->phy; -	u32 hf; +	u64 hf;  	u16 tmp;  	int autodiv = 0; @@ -2452,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)  	for (i = 0; i < 64; i++) {  		tmp = b43_nrssi_hw_read(dev, i);  		tmp -= val; -		tmp = limit_value(tmp, -32, 31); +		tmp = clamp_val(tmp, -32, 31);  		b43_nrssi_hw_write(dev, i, tmp);  	}  } @@ -2469,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev)  		tmp = (i - delta) * phy->nrssislope;  		tmp /= 0x10000;  		tmp += 0x3A; -		tmp = limit_value(tmp, 0, 0x3F); +		tmp = clamp_val(tmp, 0, 0x3F);  		phy->nrssi_lt[i] = tmp;  	}  } @@ -2906,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)  			} else  				threshold = phy->nrssi[1] - 5; -			threshold = limit_value(threshold, 0, 0x3E); +			threshold = clamp_val(threshold, 0, 0x3E);  			b43_phy_read(dev, 0x0020);	/* dummy read */  			b43_phy_write(dev, 0x0020,  				      (((u16) threshold) << 8) | 0x001C); @@ -2957,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)  			else  				a += 32;  			a = a >> 6; -			a = limit_value(a, -31, 31); +			a = clamp_val(a, -31, 31);  			b = b * (phy->nrssi[1] - phy->nrssi[0]);  			b += (phy->nrssi[0] << 6); @@ -2966,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)  			else  				b += 32;  			b = b >> 6; -			b = limit_value(b, -31, 31); +			b = clamp_val(b, -31, 31);  			tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;  			tmp_u16 |= ((u32) b & 0x0000003F); @@ -3069,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)  		}  		radio_stacksave(0x0078);  		tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); -		flipped = flip_4bit(tmp); +		B43_WARN_ON(tmp > 15); +		flipped = bitrev4(tmp);  		if (flipped < 10 && flipped >= 8)  			flipped = 7;  		else if (flipped >= 10)  			flipped -= 3; -		flipped = flip_4bit(flipped); -		flipped = (flipped << 1) | 0x0020; +		flipped = (bitrev4(flipped) << 1) | 0x0020;  		b43_radio_write16(dev, 0x0078, flipped);  		b43_calc_nrssi_threshold(dev); @@ -3708,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)  	tmp1 >>= 9;  	for (i = 0; i < 16; i++) { -		radio78 = ((flip_4bit(i) << 1) | 0x20); +		radio78 = (bitrev4(i) << 1) | 0x0020;  		b43_radio_write16(dev, 0x78, radio78);  		udelay(10);  		for (j = 0; j < 16; j++) { diff --git a/package/b43/src/phy.h b/package/b43/src/phy.h index 6d165d822..4aab10903 100644 --- a/package/b43/src/phy.h +++ b/package/b43/src/phy.h @@ -225,7 +225,6 @@ int b43_phy_init(struct b43_wldev *dev);  void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);  void b43_phy_xmitpower(struct b43_wldev *dev); -void b43_gphy_dc_lt_init(struct b43_wldev *dev);  /* Returns the boolean whether the board has HardwarePowerControl */  bool b43_has_hardware_pctl(struct b43_phy *phy); @@ -252,6 +251,14 @@ struct b43_rfatt_list {  	u8 max_val;  }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, +				     const struct b43_rfatt *b) +{ +	return ((a->att == b->att) && +		(a->with_padmix == b->with_padmix)); +} +  /* Baseband Attenuation */  struct b43_bbatt {  	u8 att;			/* Attenuation value */ @@ -265,6 +272,13 @@ struct b43_bbatt_list {  	u8 max_val;  }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, +				     const struct b43_bbatt *b) +{ +	return (a->att == b->att); +} +  /* tx_control bits. */  #define B43_TXCTL_PA3DB		0x40	/* PA Gain 3dB */  #define B43_TXCTL_PA2DB		0x20	/* PA Gain 2dB */ diff --git a/package/b43/src/pio.c b/package/b43/src/pio.c new file mode 100644 index 000000000..8b1555d95 --- /dev/null +++ b/package/b43/src/pio.c @@ -0,0 +1,842 @@ +/* + +  Broadcom B43 wireless driver + +  PIO data transfer + +  Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de> + +  This program is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  This program is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License +  along with this program; see the file COPYING.  If not, write to +  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, +  Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "pio.h" +#include "dma.h" +#include "main.h" +#include "xmit.h" + +#include <linux/delay.h> + + +static void b43_pio_rx_work(struct work_struct *work); + + +static u16 generate_cookie(struct b43_pio_txqueue *q, +			   struct b43_pio_txpacket *pack) +{ +	u16 cookie; + +	/* Use the upper 4 bits of the cookie as +	 * PIO controller ID and store the packet index number +	 * in the lower 12 bits. +	 * Note that the cookie must never be 0, as this +	 * is a special value used in RX path. +	 * It can also not be 0xFFFF because that is special +	 * for multicast frames. +	 */ +	cookie = (((u16)q->index + 1) << 12); +	cookie |= pack->index; + +	return cookie; +} + +static +struct b43_pio_txqueue * parse_cookie(struct b43_wldev *dev, +				      u16 cookie, +				      struct b43_pio_txpacket **pack) +{ +	struct b43_pio *pio = &dev->pio; +	struct b43_pio_txqueue *q = NULL; +	unsigned int pack_index; + +	switch (cookie & 0xF000) { +	case 0x1000: +		q = pio->tx_queue_AC_BK; +		break; +	case 0x2000: +		q = pio->tx_queue_AC_BE; +		break; +	case 0x3000: +		q = pio->tx_queue_AC_VI; +		break; +	case 0x4000: +		q = pio->tx_queue_AC_VO; +		break; +	case 0x5000: +		q = pio->tx_queue_mcast; +		break; +	} +	if (B43_WARN_ON(!q)) +		return NULL; +	pack_index = (cookie & 0x0FFF); +	if (B43_WARN_ON(pack_index >= ARRAY_SIZE(q->packets))) +		return NULL; +	*pack = &q->packets[pack_index]; + +	return q; +} + +static u16 index_to_pioqueue_base(struct b43_wldev *dev, +				  unsigned int index) +{ +	static const u16 bases[] = { +		B43_MMIO_PIO_BASE0, +		B43_MMIO_PIO_BASE1, +		B43_MMIO_PIO_BASE2, +		B43_MMIO_PIO_BASE3, +		B43_MMIO_PIO_BASE4, +		B43_MMIO_PIO_BASE5, +		B43_MMIO_PIO_BASE6, +		B43_MMIO_PIO_BASE7, +	}; +	static const u16 bases_rev11[] = { +		B43_MMIO_PIO11_BASE0, +		B43_MMIO_PIO11_BASE1, +		B43_MMIO_PIO11_BASE2, +		B43_MMIO_PIO11_BASE3, +		B43_MMIO_PIO11_BASE4, +		B43_MMIO_PIO11_BASE5, +	}; + +	if (dev->dev->id.revision >= 11) { +		B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11)); +		return bases_rev11[index]; +	} +	B43_WARN_ON(index >= ARRAY_SIZE(bases)); +	return bases[index]; +} + +static u16 pio_txqueue_offset(struct b43_wldev *dev) +{ +	if (dev->dev->id.revision >= 11) +		return 0x18; +	return 0; +} + +static u16 pio_rxqueue_offset(struct b43_wldev *dev) +{ +	if (dev->dev->id.revision >= 11) +		return 0x38; +	return 8; +} + +static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev, +						      unsigned int index) +{ +	struct b43_pio_txqueue *q; +	struct b43_pio_txpacket *p; +	unsigned int i; + +	q = kzalloc(sizeof(*q), GFP_KERNEL); +	if (!q) +		return NULL; +	spin_lock_init(&q->lock); +	q->dev = dev; +	q->rev = dev->dev->id.revision; +	q->mmio_base = index_to_pioqueue_base(dev, index) + +		       pio_txqueue_offset(dev); +	q->index = index; + +	q->free_packet_slots = B43_PIO_MAX_NR_TXPACKETS; +	if (q->rev >= 8) { +		q->buffer_size = 1920; //FIXME this constant is wrong. +	} else { +		q->buffer_size = b43_piotx_read16(q, B43_PIO_TXQBUFSIZE); +		q->buffer_size -= 80; +	} + +	INIT_LIST_HEAD(&q->packets_list); +	for (i = 0; i < ARRAY_SIZE(q->packets); i++) { +		p = &(q->packets[i]); +		INIT_LIST_HEAD(&p->list); +		p->index = i; +		p->queue = q; +		list_add(&p->list, &q->packets_list); +	} + +	return q; +} + +static struct b43_pio_rxqueue * b43_setup_pioqueue_rx(struct b43_wldev *dev, +						      unsigned int index) +{ +	struct b43_pio_rxqueue *q; + +	q = kzalloc(sizeof(*q), GFP_KERNEL); +	if (!q) +		return NULL; +	spin_lock_init(&q->lock); +	q->dev = dev; +	q->rev = dev->dev->id.revision; +	q->mmio_base = index_to_pioqueue_base(dev, index) + +		       pio_rxqueue_offset(dev); +	INIT_WORK(&q->rx_work, b43_pio_rx_work); + +	/* Enable Direct FIFO RX (PIO) on the engine. */ +	b43_dma_direct_fifo_rx(dev, index, 1); + +	return q; +} + +static void b43_pio_cancel_tx_packets(struct b43_pio_txqueue *q) +{ +	struct b43_pio_txpacket *pack; +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(q->packets); i++) { +		pack = &(q->packets[i]); +		if (pack->skb) { +			dev_kfree_skb_any(pack->skb); +			pack->skb = NULL; +		} +	} +} + +static void b43_destroy_pioqueue_tx(struct b43_pio_txqueue *q, +				    const char *name) +{ +	if (!q) +		return; +	b43_pio_cancel_tx_packets(q); +	kfree(q); +} + +static void b43_destroy_pioqueue_rx(struct b43_pio_rxqueue *q, +				    const char *name) +{ +	if (!q) +		return; +	kfree(q); +} + +#define destroy_queue_tx(pio, queue) do {				\ +	b43_destroy_pioqueue_tx((pio)->queue, __stringify(queue));	\ +	(pio)->queue = NULL;						\ +  } while (0) + +#define destroy_queue_rx(pio, queue) do {				\ +	b43_destroy_pioqueue_rx((pio)->queue, __stringify(queue));	\ +	(pio)->queue = NULL;						\ +  } while (0) + +void b43_pio_free(struct b43_wldev *dev) +{ +	struct b43_pio *pio; + +	if (!b43_using_pio_transfers(dev)) +		return; +	pio = &dev->pio; + +	destroy_queue_rx(pio, rx_queue); +	destroy_queue_tx(pio, tx_queue_mcast); +	destroy_queue_tx(pio, tx_queue_AC_VO); +	destroy_queue_tx(pio, tx_queue_AC_VI); +	destroy_queue_tx(pio, tx_queue_AC_BE); +	destroy_queue_tx(pio, tx_queue_AC_BK); +} + +void b43_pio_stop(struct b43_wldev *dev) +{ +	if (!b43_using_pio_transfers(dev)) +		return; +	cancel_work_sync(&dev->pio.rx_queue->rx_work); +} + +int b43_pio_init(struct b43_wldev *dev) +{ +	struct b43_pio *pio = &dev->pio; +	int err = -ENOMEM; + +	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) +		    & ~B43_MACCTL_BE); +	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RXPADOFF, 0); + +	pio->tx_queue_AC_BK = b43_setup_pioqueue_tx(dev, 0); +	if (!pio->tx_queue_AC_BK) +		goto out; + +	pio->tx_queue_AC_BE = b43_setup_pioqueue_tx(dev, 1); +	if (!pio->tx_queue_AC_BE) +		goto err_destroy_bk; + +	pio->tx_queue_AC_VI = b43_setup_pioqueue_tx(dev, 2); +	if (!pio->tx_queue_AC_VI) +		goto err_destroy_be; + +	pio->tx_queue_AC_VO = b43_setup_pioqueue_tx(dev, 3); +	if (!pio->tx_queue_AC_VO) +		goto err_destroy_vi; + +	pio->tx_queue_mcast = b43_setup_pioqueue_tx(dev, 4); +	if (!pio->tx_queue_mcast) +		goto err_destroy_vo; + +	pio->rx_queue = b43_setup_pioqueue_rx(dev, 0); +	if (!pio->rx_queue) +		goto err_destroy_mcast; + +	b43dbg(dev->wl, "PIO initialized\n"); +	err = 0; +out: +	return err; + +err_destroy_mcast: +	destroy_queue_tx(pio, tx_queue_mcast); +err_destroy_vo: +	destroy_queue_tx(pio, tx_queue_AC_VO); +err_destroy_vi: +	destroy_queue_tx(pio, tx_queue_AC_VI); +err_destroy_be: +	destroy_queue_tx(pio, tx_queue_AC_BE); +err_destroy_bk: +	destroy_queue_tx(pio, tx_queue_AC_BK); +	return err; +} + +/* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */ +static struct b43_pio_txqueue * select_queue_by_priority(struct b43_wldev *dev, +							 u8 queue_prio) +{ +	struct b43_pio_txqueue *q; + +	if (b43_modparam_qos) { +		/* 0 = highest priority */ +		switch (queue_prio) { +		default: +			B43_WARN_ON(1); +			/* fallthrough */ +		case 0: +			q = dev->pio.tx_queue_AC_VO; +			break; +		case 1: +			q = dev->pio.tx_queue_AC_VI; +			break; +		case 2: +			q = dev->pio.tx_queue_AC_BE; +			break; +		case 3: +			q = dev->pio.tx_queue_AC_BK; +			break; +		} +	} else +		q = dev->pio.tx_queue_AC_BE; + +	return q; +} + +static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q, +				u16 ctl, +				const void *_data, +				unsigned int data_len) +{ +	struct b43_wldev *dev = q->dev; +	const u8 *data = _data; + +	ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI; +	b43_piotx_write16(q, B43_PIO_TXCTL, ctl); + +	ssb_block_write(dev->dev, data, (data_len & ~1), +			q->mmio_base + B43_PIO_TXDATA, +			sizeof(u16)); +	if (data_len & 1) { +		/* Write the last byte. */ +		ctl &= ~B43_PIO_TXCTL_WRITEHI; +		b43_piotx_write16(q, B43_PIO_TXCTL, ctl); +		b43_piotx_write16(q, B43_PIO_TXDATA, data[data_len - 1]); +	} + +	return ctl; +} + +static void pio_tx_frame_2byte_queue(struct b43_pio_txpacket *pack, +				     const u8 *hdr, unsigned int hdrlen) +{ +	struct b43_pio_txqueue *q = pack->queue; +	const char *frame = pack->skb->data; +	unsigned int frame_len = pack->skb->len; +	u16 ctl; + +	ctl = b43_piotx_read16(q, B43_PIO_TXCTL); +	ctl |= B43_PIO_TXCTL_FREADY; +	ctl &= ~B43_PIO_TXCTL_EOF; + +	/* Transfer the header data. */ +	ctl = tx_write_2byte_queue(q, ctl, hdr, hdrlen); +	/* Transfer the frame data. */ +	ctl = tx_write_2byte_queue(q, ctl, frame, frame_len); + +	ctl |= B43_PIO_TXCTL_EOF; +	b43_piotx_write16(q, B43_PIO_TXCTL, ctl); +} + +static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q, +				u32 ctl, +				const void *_data, +				unsigned int data_len) +{ +	struct b43_wldev *dev = q->dev; +	const u8 *data = _data; + +	ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 | +	       B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31; +	b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); + +	ssb_block_write(dev->dev, data, (data_len & ~3), +			q->mmio_base + B43_PIO8_TXDATA, +			sizeof(u32)); +	if (data_len & 3) { +		u32 value = 0; + +		/* Write the last few bytes. */ +		ctl &= ~(B43_PIO8_TXCTL_8_15 | B43_PIO8_TXCTL_16_23 | +			 B43_PIO8_TXCTL_24_31); +		data = &(data[data_len - 1]); +		switch (data_len & 3) { +		case 3: +			ctl |= B43_PIO8_TXCTL_16_23; +			value |= (u32)(*data) << 16; +			data--; +		case 2: +			ctl |= B43_PIO8_TXCTL_8_15; +			value |= (u32)(*data) << 8; +			data--; +		case 1: +			value |= (u32)(*data); +		} +		b43_piotx_write32(q, B43_PIO8_TXCTL, ctl); +		b43_piotx_write32(q, B43_PIO8_TXDATA, value); +	} + +	return ctl; +} + +static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, +				     const u8 *hdr, unsigned int hdrlen) +{ +	struct b43_pio_txqueue *q = pack->queue; +	const char *frame = pack->skb->data; +	unsigned int frame_len = pack->skb->len; +	u32 ctl; + +	ctl = b43_piotx_read32(q, B43_PIO8_TXCTL); +	ctl |= B43_PIO8_TXCTL_FREADY; +	ctl &= ~B43_PIO8_TXCTL_EOF; + +	/* Transfer the header data. */ +	ctl = tx_write_4byte_queue(q, ctl, hdr, hdrlen); +	/* Transfer the frame data. */ +	ctl = tx_write_4byte_queue(q, ctl, frame, frame_len); + +	ctl |= B43_PIO8_TXCTL_EOF; +	b43_piotx_write32(q, B43_PIO_TXCTL, ctl); +} + +static int pio_tx_frame(struct b43_pio_txqueue *q, +			struct sk_buff *skb) +{ +	struct b43_pio_txpacket *pack; +	struct b43_txhdr txhdr; +	u16 cookie; +	int err; +	unsigned int hdrlen; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + +	B43_WARN_ON(list_empty(&q->packets_list)); +	pack = list_entry(q->packets_list.next, +			  struct b43_pio_txpacket, list); + +	cookie = generate_cookie(q, pack); +	hdrlen = b43_txhdr_size(q->dev); +	err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, +				 skb->len, info, cookie); +	if (err) +		return err; + +	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { +		/* Tell the firmware about the cookie of the last +		 * mcast frame, so it can clear the more-data bit in it. */ +		b43_shm_write16(q->dev, B43_SHM_SHARED, +				B43_SHM_SH_MCASTCOOKIE, cookie); +	} + +	pack->skb = skb; +	if (q->rev >= 8) +		pio_tx_frame_4byte_queue(pack, (const u8 *)&txhdr, hdrlen); +	else +		pio_tx_frame_2byte_queue(pack, (const u8 *)&txhdr, hdrlen); + +	/* Remove it from the list of available packet slots. +	 * It will be put back when we receive the status report. */ +	list_del(&pack->list); + +	/* Update the queue statistics. */ +	q->buffer_used += roundup(skb->len + hdrlen, 4); +	q->free_packet_slots -= 1; + +	return 0; +} + +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) +{ +	struct b43_pio_txqueue *q; +	struct ieee80211_hdr *hdr; +	unsigned long flags; +	unsigned int hdrlen, total_len; +	int err = 0; +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + +	hdr = (struct ieee80211_hdr *)skb->data; + +	if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { +		/* The multicast queue will be sent after the DTIM. */ +		q = dev->pio.tx_queue_mcast; +		/* Set the frame More-Data bit. Ucode will clear it +		 * for us on the last frame. */ +		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); +	} else { +		/* Decide by priority where to put this frame. */ +		q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); +	} + +	spin_lock_irqsave(&q->lock, flags); + +	hdrlen = b43_txhdr_size(dev); +	total_len = roundup(skb->len + hdrlen, 4); + +	if (unlikely(total_len > q->buffer_size)) { +		err = -ENOBUFS; +		b43dbg(dev->wl, "PIO: TX packet longer than queue.\n"); +		goto out_unlock; +	} +	if (unlikely(q->free_packet_slots == 0)) { +		err = -ENOBUFS; +		b43warn(dev->wl, "PIO: TX packet overflow.\n"); +		goto out_unlock; +	} +	B43_WARN_ON(q->buffer_used > q->buffer_size); + +	if (total_len > (q->buffer_size - q->buffer_used)) { +		/* Not enough memory on the queue. */ +		err = -EBUSY; +		ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); +		q->stopped = 1; +		goto out_unlock; +	} + +	/* Assign the queue number to the ring (if not already done before) +	 * so TX status handling can use it. The mac80211-queue to b43-queue +	 * mapping is static, so we don't need to store it per frame. */ +	q->queue_prio = skb_get_queue_mapping(skb); + +	err = pio_tx_frame(q, skb); +	if (unlikely(err == -ENOKEY)) { +		/* Drop this packet, as we don't have the encryption key +		 * anymore and must not transmit it unencrypted. */ +		dev_kfree_skb_any(skb); +		err = 0; +		goto out_unlock; +	} +	if (unlikely(err)) { +		b43err(dev->wl, "PIO transmission failure\n"); +		goto out_unlock; +	} +	q->nr_tx_packets++; + +	B43_WARN_ON(q->buffer_used > q->buffer_size); +	if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || +	    (q->free_packet_slots == 0)) { +		/* The queue is full. */ +		ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); +		q->stopped = 1; +	} + +out_unlock: +	spin_unlock_irqrestore(&q->lock, flags); + +	return err; +} + +/* Called with IRQs disabled. */ +void b43_pio_handle_txstatus(struct b43_wldev *dev, +			     const struct b43_txstatus *status) +{ +	struct b43_pio_txqueue *q; +	struct b43_pio_txpacket *pack = NULL; +	unsigned int total_len; +	struct ieee80211_tx_info *info; + +	q = parse_cookie(dev, status->cookie, &pack); +	if (unlikely(!q)) +		return; +	B43_WARN_ON(!pack); + +	spin_lock(&q->lock); /* IRQs are already disabled. */ + +	info = (void *)pack->skb; +	memset(&info->status, 0, sizeof(info->status)); + +	b43_fill_txstatus_report(info, status); + +	total_len = pack->skb->len + b43_txhdr_size(dev); +	total_len = roundup(total_len, 4); +	q->buffer_used -= total_len; +	q->free_packet_slots += 1; + +	ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); +	pack->skb = NULL; +	list_add(&pack->list, &q->packets_list); + +	if (q->stopped) { +		ieee80211_wake_queue(dev->wl->hw, q->queue_prio); +		q->stopped = 0; +	} + +	spin_unlock(&q->lock); +} + +void b43_pio_get_tx_stats(struct b43_wldev *dev, +			  struct ieee80211_tx_queue_stats *stats) +{ +	const int nr_queues = dev->wl->hw->queues; +	struct b43_pio_txqueue *q; +	unsigned long flags; +	int i; + +	for (i = 0; i < nr_queues; i++) { +		q = select_queue_by_priority(dev, i); + +		spin_lock_irqsave(&q->lock, flags); +		stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; +		stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; +		stats[i].count = q->nr_tx_packets; +		spin_unlock_irqrestore(&q->lock, flags); +	} +} + +/* Returns whether we should fetch another frame. */ +static bool pio_rx_frame(struct b43_pio_rxqueue *q) +{ +	struct b43_wldev *dev = q->dev; +	struct b43_rxhdr_fw4 rxhdr; +	u16 len; +	u32 macstat; +	unsigned int i, padding; +	struct sk_buff *skb; +	const char *err_msg = NULL; + +	memset(&rxhdr, 0, sizeof(rxhdr)); + +	/* Check if we have data and wait for it to get ready. */ +	if (q->rev >= 8) { +		u32 ctl; + +		ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); +		if (!(ctl & B43_PIO8_RXCTL_FRAMERDY)) +			return 0; +		b43_piorx_write32(q, B43_PIO8_RXCTL, +				  B43_PIO8_RXCTL_FRAMERDY); +		for (i = 0; i < 10; i++) { +			ctl = b43_piorx_read32(q, B43_PIO8_RXCTL); +			if (ctl & B43_PIO8_RXCTL_DATARDY) +				goto data_ready; +			udelay(10); +		} +	} else { +		u16 ctl; + +		ctl = b43_piorx_read16(q, B43_PIO_RXCTL); +		if (!(ctl & B43_PIO_RXCTL_FRAMERDY)) +			return 0; +		b43_piorx_write16(q, B43_PIO_RXCTL, +				  B43_PIO_RXCTL_FRAMERDY); +		for (i = 0; i < 10; i++) { +			ctl = b43_piorx_read16(q, B43_PIO_RXCTL); +			if (ctl & B43_PIO_RXCTL_DATARDY) +				goto data_ready; +			udelay(10); +		} +	} +	b43dbg(q->dev->wl, "PIO RX timed out\n"); +	return 1; +data_ready: + +	/* Get the preamble (RX header) */ +	if (q->rev >= 8) { +		ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr), +			       q->mmio_base + B43_PIO8_RXDATA, +			       sizeof(u32)); +	} else { +		ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr), +			       q->mmio_base + B43_PIO_RXDATA, +			       sizeof(u16)); +	} +	/* Sanity checks. */ +	len = le16_to_cpu(rxhdr.frame_len); +	if (unlikely(len > 0x700)) { +		err_msg = "len > 0x700"; +		goto rx_error; +	} +	if (unlikely(len == 0)) { +		err_msg = "len == 0"; +		goto rx_error; +	} + +	macstat = le32_to_cpu(rxhdr.mac_status); +	if (macstat & B43_RX_MAC_FCSERR) { +		if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) { +			/* Drop frames with failed FCS. */ +			err_msg = "Frame FCS error"; +			goto rx_error; +		} +	} + +	/* We always pad 2 bytes, as that's what upstream code expects +	 * due to the RX-header being 30 bytes. In case the frame is +	 * unaligned, we pad another 2 bytes. */ +	padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0; +	skb = dev_alloc_skb(len + padding + 2); +	if (unlikely(!skb)) { +		err_msg = "Out of memory"; +		goto rx_error; +	} +	skb_reserve(skb, 2); +	skb_put(skb, len + padding); +	if (q->rev >= 8) { +		ssb_block_read(dev->dev, skb->data + padding, (len & ~3), +			       q->mmio_base + B43_PIO8_RXDATA, +			       sizeof(u32)); +		if (len & 3) { +			u32 value; +			char *data; + +			/* Read the last few bytes. */ +			value = b43_piorx_read32(q, B43_PIO8_RXDATA); +			data = &(skb->data[len + padding - 1]); +			switch (len & 3) { +			case 3: +				*data = (value >> 16); +				data--; +			case 2: +				*data = (value >> 8); +				data--; +			case 1: +				*data = value; +			} +		} +	} else { +		ssb_block_read(dev->dev, skb->data + padding, (len & ~1), +			       q->mmio_base + B43_PIO_RXDATA, +			       sizeof(u16)); +		if (len & 1) { +			u16 value; + +			/* Read the last byte. */ +			value = b43_piorx_read16(q, B43_PIO_RXDATA); +			skb->data[len + padding - 1] = value; +		} +	} + +	b43_rx(q->dev, skb, &rxhdr); + +	return 1; + +rx_error: +	if (err_msg) +		b43dbg(q->dev->wl, "PIO RX error: %s\n", err_msg); +	b43_piorx_write16(q, B43_PIO_RXCTL, B43_PIO_RXCTL_DATARDY); +	return 1; +} + +/* RX workqueue. We can sleep, yay! */ +static void b43_pio_rx_work(struct work_struct *work) +{ +	struct b43_pio_rxqueue *q = container_of(work, struct b43_pio_rxqueue, +						 rx_work); +	unsigned int budget = 50; +	bool stop; + +	do { +		spin_lock_irq(&q->lock); +		stop = (pio_rx_frame(q) == 0); +		spin_unlock_irq(&q->lock); +		cond_resched(); +		if (stop) +			break; +	} while (--budget); +} + +/* Called with IRQs disabled. */ +void b43_pio_rx(struct b43_pio_rxqueue *q) +{ +	/* Due to latency issues we must run the RX path in +	 * a workqueue to be able to schedule between packets. */ +	queue_work(q->dev->wl->hw->workqueue, &q->rx_work); +} + +static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q) +{ +	unsigned long flags; + +	spin_lock_irqsave(&q->lock, flags); +	if (q->rev >= 8) { +		b43_piotx_write32(q, B43_PIO8_TXCTL, +				  b43_piotx_read32(q, B43_PIO8_TXCTL) +				  | B43_PIO8_TXCTL_SUSPREQ); +	} else { +		b43_piotx_write16(q, B43_PIO_TXCTL, +				  b43_piotx_read16(q, B43_PIO_TXCTL) +				  | B43_PIO_TXCTL_SUSPREQ); +	} +	spin_unlock_irqrestore(&q->lock, flags); +} + +static void b43_pio_tx_resume_queue(struct b43_pio_txqueue *q) +{ +	unsigned long flags; + +	spin_lock_irqsave(&q->lock, flags); +	if (q->rev >= 8) { +		b43_piotx_write32(q, B43_PIO8_TXCTL, +				  b43_piotx_read32(q, B43_PIO8_TXCTL) +				  & ~B43_PIO8_TXCTL_SUSPREQ); +	} else { +		b43_piotx_write16(q, B43_PIO_TXCTL, +				  b43_piotx_read16(q, B43_PIO_TXCTL) +				  & ~B43_PIO_TXCTL_SUSPREQ); +	} +	spin_unlock_irqrestore(&q->lock, flags); +} + +void b43_pio_tx_suspend(struct b43_wldev *dev) +{ +	b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); +	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BK); +	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_BE); +	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VI); +	b43_pio_tx_suspend_queue(dev->pio.tx_queue_AC_VO); +	b43_pio_tx_suspend_queue(dev->pio.tx_queue_mcast); +} + +void b43_pio_tx_resume(struct b43_wldev *dev) +{ +	b43_pio_tx_resume_queue(dev->pio.tx_queue_mcast); +	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VO); +	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_VI); +	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BE); +	b43_pio_tx_resume_queue(dev->pio.tx_queue_AC_BK); +	b43_power_saving_ctl_bits(dev, 0); +} diff --git a/package/b43/src/pio.h b/package/b43/src/pio.h new file mode 100644 index 000000000..6c174c91c --- /dev/null +++ b/package/b43/src/pio.h @@ -0,0 +1,216 @@ +#ifndef B43_PIO_H_ +#define B43_PIO_H_ + +#include "b43.h" + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/skbuff.h> + + +/*** Registers for PIO queues up to revision 7. ***/ +/* TX queue. */ +#define B43_PIO_TXCTL			0x00 +#define  B43_PIO_TXCTL_WRITELO		0x0001 +#define  B43_PIO_TXCTL_WRITEHI		0x0002 +#define  B43_PIO_TXCTL_EOF		0x0004 +#define  B43_PIO_TXCTL_FREADY		0x0008 +#define  B43_PIO_TXCTL_FLUSHREQ		0x0020 +#define  B43_PIO_TXCTL_FLUSHPEND	0x0040 +#define  B43_PIO_TXCTL_SUSPREQ		0x0080 +#define  B43_PIO_TXCTL_QSUSP		0x0100 +#define  B43_PIO_TXCTL_COMMCNT		0xFC00 +#define  B43_PIO_TXCTL_COMMCNT_SHIFT	10 +#define B43_PIO_TXDATA			0x02 +#define B43_PIO_TXQBUFSIZE		0x04 +/* RX queue. */ +#define B43_PIO_RXCTL			0x00 +#define  B43_PIO_RXCTL_FRAMERDY		0x0001 +#define  B43_PIO_RXCTL_DATARDY		0x0002 +#define B43_PIO_RXDATA			0x02 + +/*** Registers for PIO queues revision 8 and later. ***/ +/* TX queue */ +#define B43_PIO8_TXCTL			0x00 +#define  B43_PIO8_TXCTL_0_7		0x00000001 +#define  B43_PIO8_TXCTL_8_15		0x00000002 +#define  B43_PIO8_TXCTL_16_23		0x00000004 +#define  B43_PIO8_TXCTL_24_31		0x00000008 +#define  B43_PIO8_TXCTL_EOF		0x00000010 +#define  B43_PIO8_TXCTL_FREADY		0x00000080 +#define  B43_PIO8_TXCTL_SUSPREQ		0x00000100 +#define  B43_PIO8_TXCTL_QSUSP		0x00000200 +#define  B43_PIO8_TXCTL_FLUSHREQ	0x00000400 +#define  B43_PIO8_TXCTL_FLUSHPEND	0x00000800 +#define B43_PIO8_TXDATA			0x04 +/* RX queue */ +#define B43_PIO8_RXCTL			0x00 +#define  B43_PIO8_RXCTL_FRAMERDY	0x00000001 +#define  B43_PIO8_RXCTL_DATARDY		0x00000002 +#define B43_PIO8_RXDATA			0x04 + + +/* The maximum number of TX-packets the HW can handle. */ +#define B43_PIO_MAX_NR_TXPACKETS	32 + + +#ifdef CONFIG_B43_PIO + +struct b43_pio_txpacket { +	/* Pointer to the TX queue we belong to. */ +	struct b43_pio_txqueue *queue; +	/* The TX data packet. */ +	struct sk_buff *skb; +	/* Index in the (struct b43_pio_txqueue)->packets array. */ +	u8 index; + +	struct list_head list; +}; + +struct b43_pio_txqueue { +	struct b43_wldev *dev; +	spinlock_t lock; +	u16 mmio_base; + +	/* The device queue buffer size in bytes. */ +	u16 buffer_size; +	/* The number of used bytes in the device queue buffer. */ +	u16 buffer_used; +	/* The number of packets that can still get queued. +	 * This is decremented on queueing a packet and incremented +	 * after receiving the transmit status. */ +	u16 free_packet_slots; + +	/* True, if the mac80211 queue was stopped due to overflow at TX. */ +	bool stopped; +	/* Our b43 queue index number */ +	u8 index; +	/* The mac80211 QoS queue priority. */ +	u8 queue_prio; + +	/* Buffer for TX packet meta data. */ +	struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS]; +	struct list_head packets_list; + +	/* Total number of transmitted packets. */ +	unsigned int nr_tx_packets; + +	/* Shortcut to the 802.11 core revision. This is to +	 * avoid horrible pointer dereferencing in the fastpaths. */ +	u8 rev; +}; + +struct b43_pio_rxqueue { +	struct b43_wldev *dev; +	spinlock_t lock; +	u16 mmio_base; + +	/* Work to reduce latency issues on RX. */ +	struct work_struct rx_work; + +	/* Shortcut to the 802.11 core revision. This is to +	 * avoid horrible pointer dereferencing in the fastpaths. */ +	u8 rev; +}; + + +static inline u16 b43_piotx_read16(struct b43_pio_txqueue *q, u16 offset) +{ +	return b43_read16(q->dev, q->mmio_base + offset); +} + +static inline u32 b43_piotx_read32(struct b43_pio_txqueue *q, u16 offset) +{ +	return b43_read32(q->dev, q->mmio_base + offset); +} + +static inline void b43_piotx_write16(struct b43_pio_txqueue *q, +				     u16 offset, u16 value) +{ +	b43_write16(q->dev, q->mmio_base + offset, value); +} + +static inline void b43_piotx_write32(struct b43_pio_txqueue *q, +				     u16 offset, u32 value) +{ +	b43_write32(q->dev, q->mmio_base + offset, value); +} + + +static inline u16 b43_piorx_read16(struct b43_pio_rxqueue *q, u16 offset) +{ +	return b43_read16(q->dev, q->mmio_base + offset); +} + +static inline u32 b43_piorx_read32(struct b43_pio_rxqueue *q, u16 offset) +{ +	return b43_read32(q->dev, q->mmio_base + offset); +} + +static inline void b43_piorx_write16(struct b43_pio_rxqueue *q, +				     u16 offset, u16 value) +{ +	b43_write16(q->dev, q->mmio_base + offset, value); +} + +static inline void b43_piorx_write32(struct b43_pio_rxqueue *q, +				     u16 offset, u32 value) +{ +	b43_write32(q->dev, q->mmio_base + offset, value); +} + + +int b43_pio_init(struct b43_wldev *dev); +void b43_pio_stop(struct b43_wldev *dev); +void b43_pio_free(struct b43_wldev *dev); + +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); +void b43_pio_handle_txstatus(struct b43_wldev *dev, +			     const struct b43_txstatus *status); +void b43_pio_get_tx_stats(struct b43_wldev *dev, +			  struct ieee80211_tx_queue_stats *stats); +void b43_pio_rx(struct b43_pio_rxqueue *q); + +void b43_pio_tx_suspend(struct b43_wldev *dev); +void b43_pio_tx_resume(struct b43_wldev *dev); + + +#else /* CONFIG_B43_PIO */ + + +static inline int b43_pio_init(struct b43_wldev *dev) +{ +	return 0; +} +static inline void b43_pio_free(struct b43_wldev *dev) +{ +} +static inline void b43_pio_stop(struct b43_wldev *dev) +{ +} +static inline int b43_pio_tx(struct b43_wldev *dev, +			     struct sk_buff *skb) +{ +	return 0; +} +static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, +					   const struct b43_txstatus *status) +{ +} +static inline void b43_pio_get_tx_stats(struct b43_wldev *dev, +					struct ieee80211_tx_queue_stats *stats) +{ +} +static inline void b43_pio_rx(struct b43_pio_rxqueue *q) +{ +} +static inline void b43_pio_tx_suspend(struct b43_wldev *dev) +{ +} +static inline void b43_pio_tx_resume(struct b43_wldev *dev) +{ +} + +#endif /* CONFIG_B43_PIO */ +#endif /* B43_PIO_H_ */ diff --git a/package/b43/src/wa.c b/package/b43/src/wa.c index e632125cb..daa94211f 100644 --- a/package/b43/src/wa.c +++ b/package/b43/src/wa.c @@ -204,42 +204,43 @@ static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */  		b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);  } +static void b43_write_null_nst(struct b43_wldev *dev) +{ +	int i; + +	for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) +		b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, 0); +} + +static void b43_write_nst(struct b43_wldev *dev, const u16 *nst) +{ +	int i; + +	for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) +		b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, nst[i]); +} +  static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */  {  	struct b43_phy *phy = &dev->phy; -	int i;  	if (phy->type == B43_PHYTYPE_A) {  		if (phy->rev <= 1) -			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -							i, 0); +			b43_write_null_nst(dev);  		else if (phy->rev == 2) -			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -							i, b43_tab_noisescalea2[i]); +			b43_write_nst(dev, b43_tab_noisescalea2);  		else if (phy->rev == 3) -			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -							i, b43_tab_noisescalea3[i]); +			b43_write_nst(dev, b43_tab_noisescalea3);  		else -			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -							i, b43_tab_noisescaleg3[i]); +			b43_write_nst(dev, b43_tab_noisescaleg3);  	} else {  		if (phy->rev >= 6) {  			if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) -				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -						i, b43_tab_noisescaleg3[i]); +				b43_write_nst(dev, b43_tab_noisescaleg3);  			else -				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -						i, b43_tab_noisescaleg2[i]); +				b43_write_nst(dev, b43_tab_noisescaleg2);  		} else { -			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) -				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, -							i, b43_tab_noisescaleg1[i]); +			b43_write_nst(dev, b43_tab_noisescaleg1);  		}  	}  } diff --git a/package/b43/src/xmit.c b/package/b43/src/xmit.c index 4014b6c82..f9e1cff2a 100644 --- a/package/b43/src/xmit.c +++ b/package/b43/src/xmit.c @@ -30,6 +30,7 @@  #include "xmit.h"  #include "phy.h"  #include "dma.h" +#include "pio.h"  /* Extract the bitrate index out of a CCK PLCP header. */ @@ -184,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		       u8 *_txhdr,  		       const unsigned char *fragment_data,  		       unsigned int fragment_len, -		       const struct ieee80211_tx_control *txctl, +		       const struct ieee80211_tx_info *info,  		       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; -	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); +	int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));  	u16 fctl = le16_to_cpu(wlhdr->frame_control);  	struct ieee80211_rate *fbrate;  	u8 rate, rate_fb; @@ -200,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	u32 mac_ctl = 0;  	u16 phy_ctl = 0;  	u8 extra_ft = 0; +	struct ieee80211_rate *txrate;  	memset(txhdr, 0, sizeof(*txhdr)); -	WARN_ON(!txctl->tx_rate); -	rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; +	txrate = ieee80211_get_tx_rate(dev->wl->hw, info); +	rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;  	rate_ofdm = b43_is_ofdm_rate(rate); -	fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; +	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;  	rate_fb = fbrate->hw_value;  	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -226,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		 * use the original dur_id field. */  		txhdr->dur_fb = wlhdr->duration_id;  	} else { -		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, -								 txctl->vif, -								 fragment_len, -								 fbrate); +		txhdr->dur_fb = ieee80211_generic_frame_duration( +			dev->wl->hw, info->control.vif, fragment_len, fbrate);  	}  	plcp_fragment_len = fragment_len + FCS_LEN;  	if (use_encryption) { -		u8 key_idx = (u16) (txctl->key_idx); +		u8 key_idx = info->control.hw_key->hw_key_idx;  		struct b43_key *key;  		int wlhdr_len;  		size_t iv_len; @@ -252,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		}  		/* Hardware appends ICV. */ -		plcp_fragment_len += txctl->icv_len; +		plcp_fragment_len += info->control.icv_len;  		key_idx = b43_kidx_to_fw(dev, key_idx);  		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & @@ -260,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		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, +		iv_len = min((size_t) info->control.iv_len,  			     ARRAY_SIZE(txhdr->iv));  		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);  	} @@ -291,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,  		phy_ctl |= B43_TXH_PHY_ENC_OFDM;  	else  		phy_ctl |= B43_TXH_PHY_ENC_CCK; -	if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) +	if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)  		phy_ctl |= B43_TXH_PHY_SHORTPRMBL; -	switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { +	switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {  	case 0: /* Default */  		phy_ctl |= B43_TXH_PHY_ANT01AUTO;  		break; @@ -315,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,  	}  	/* MAC control */ -	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) +	if (!(info->flags & IEEE80211_TX_CTL_NO_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_TXH_MAC_HWSEQ; -	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) +	if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)  		mac_ctl |= B43_TXH_MAC_STMSDU;  	if (phy->type == B43_PHYTYPE_A)  		mac_ctl |= B43_TXH_MAC_5GHZ; -	if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) +	if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)  		mac_ctl |= B43_TXH_MAC_LONGFRAME;  	/* Generate the RTS or CTS-to-self frame */ -	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || -	    (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { +	if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || +	    (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {  		unsigned int len;  		struct ieee80211_hdr *hdr;  		int rts_rate, rts_rate_fb;  		int rts_rate_ofdm, rts_rate_fb_ofdm;  		struct b43_plcp_hdr6 *plcp; +		struct ieee80211_rate *rts_cts_rate; -		WARN_ON(!txctl->rts_cts_rate); -		rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; +		rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); + +		rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;  		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);  		rts_rate_fb = b43_calc_fallback_rate(rts_rate);  		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); -		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { +		if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {  			struct ieee80211_cts *cts;  			if (b43_is_old_txhdr_format(dev)) { @@ -352,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,  				cts = (struct ieee80211_cts *)  					(txhdr->new_format.rts_frame);  			} -			ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, +			ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,  						fragment_data, fragment_len, -						txctl, cts); +						info, cts);  			mac_ctl |= B43_TXH_MAC_SENDCTS;  			len = sizeof(struct ieee80211_cts);  		} else { @@ -367,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,  				rts = (struct ieee80211_rts *)  					(txhdr->new_format.rts_frame);  			} -			ieee80211_rts_get(dev->wl->hw, txctl->vif, +			ieee80211_rts_get(dev->wl->hw, info->control.vif,  					  fragment_data, fragment_len, -					  txctl, rts); +					  info, rts);  			mac_ctl |= B43_TXH_MAC_SENDRTS;  			len = sizeof(struct ieee80211_rts);  		} @@ -512,7 +514,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  	u32 macstat;  	u16 chanid;  	u16 phytype; -	u8 jssi;  	int padding;  	memset(&status, 0, sizeof(status)); @@ -520,7 +521,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  	/* Get metadata about the frame from the header. */  	phystat0 = le16_to_cpu(rxhdr->phy_status0);  	phystat3 = le16_to_cpu(rxhdr->phy_status3); -	jssi = rxhdr->jssi;  	macstat = le32_to_cpu(rxhdr->mac_status);  	mactime = le16_to_cpu(rxhdr->mac_time);  	chanstat = le16_to_cpu(rxhdr->channel); @@ -574,13 +574,21 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  		}  	} -	status.ssi = b43_rssi_postprocess(dev, jssi, -					  (phystat0 & B43_RX_PHYST0_OFDM), -					  (phystat0 & B43_RX_PHYST0_GAINCTL), -					  (phystat3 & B43_RX_PHYST3_TRSTATE)); +	/* Link quality statistics */  	status.noise = dev->stats.link_noise; -	/* the next line looks wrong, but is what mac80211 wants */ -	status.signal = (jssi * 100) / B43_RX_MAX_SSI; +	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 { +		status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, +						  (phystat0 & B43_RX_PHYST0_OFDM), +						  (phystat0 & B43_RX_PHYST0_GAINCTL), +						  (phystat3 & B43_RX_PHYST3_TRSTATE)); +		status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; +	} +  	if (phystat0 & B43_RX_PHYST0_OFDM)  		status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,  						phytype == B43_PHYTYPE_A); @@ -589,12 +597,16 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)  	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);  	/* -	 * If monitors are present get full 64-bit timestamp. This -	 * code assumes we get to process the packet within 16 bits -	 * of timestamp, i.e. about 65 milliseconds after the PHY -	 * received the first symbol. +	 * All frames on monitor interfaces and beacons always need a full +	 * 64-bit timestamp. Monitor interfaces need it for diagnostic +	 * purposes and beacons for IBSS merging. +	 * This code assumes we get to process the packet within 16 bits +	 * of timestamp, i.e. about 65 milliseconds after the PHY received +	 * the first symbol.  	 */ -	if (dev->wl->radiotap_enabled) { +	if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) +	    == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || +	    dev->wl->radiotap_enabled) {  		u16 low_mactime_now;  		b43_tsf_read(dev, &status.mactime); @@ -664,67 +676,54 @@ void b43_handle_txstatus(struct b43_wldev *dev,  			dev->wl->ieee_stats.dot11RTSSuccessCount++;  	} -	b43_dma_handle_txstatus(dev, status); +	if (b43_using_pio_transfers(dev)) +		b43_pio_handle_txstatus(dev, status); +	else +		b43_dma_handle_txstatus(dev, status);  } -/* Handle TX status report as received through DMA/PIO queues */ -void b43_handle_hwtxstatus(struct b43_wldev *dev, -			   const struct b43_hwtxstatus *hw) +/* Fill out the mac80211 TXstatus report based on the b43-specific + * txstatus report data. This returns a boolean whether the frame was + * successfully transmitted. */ +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +			      const struct b43_txstatus *status)  { -	struct b43_txstatus status; -	u8 tmp; - -	status.cookie = le16_to_cpu(hw->cookie); -	status.seq = le16_to_cpu(hw->seq); -	status.phy_stat = hw->phy_stat; -	tmp = hw->count; -	status.frame_count = (tmp >> 4); -	status.rts_count = (tmp & 0x0F); -	tmp = hw->flags; -	status.supp_reason = ((tmp & 0x1C) >> 2); -	status.pm_indicated = !!(tmp & 0x80); -	status.intermediate = !!(tmp & 0x40); -	status.for_ampdu = !!(tmp & 0x20); -	status.acked = !!(tmp & 0x02); - -	b43_handle_txstatus(dev, &status); +	bool frame_success = 1; + +	if (status->acked) { +		/* The frame was ACKed. */ +		report->flags |= IEEE80211_TX_STAT_ACK; +	} else { +		/* The frame was not ACKed... */ +		if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { +			/* ...but we expected an ACK. */ +			frame_success = 0; +			report->status.excessive_retries = 1; +		} +	} +	if (status->frame_count == 0) { +		/* The frame was not transmitted at all. */ +		report->status.retry_count = 0; +	} else +		report->status.retry_count = status->frame_count - 1; + +	return frame_success;  }  /* Stop any TX operation on the device (suspend the hardware queues) */  void b43_tx_suspend(struct b43_wldev *dev)  { -	b43_dma_tx_suspend(dev); +	if (b43_using_pio_transfers(dev)) +		b43_pio_tx_suspend(dev); +	else +		b43_dma_tx_suspend(dev);  }  /* Resume any TX operation on the device (resume the hardware queues) */  void b43_tx_resume(struct b43_wldev *dev)  { -	b43_dma_tx_resume(dev); -} - -#if 0 -static void upload_qos_parms(struct b43_wldev *dev, -			     const u16 * parms, u16 offset) -{ -	int i; - -	for (i = 0; i < B43_NR_QOSPARMS; i++) { -		b43_shm_write16(dev, B43_SHM_SHARED, -				offset + (i * 2), parms[i]); -	} -} -#endif - -/* Initialize the QoS parameters */ -void b43_qos_init(struct b43_wldev *dev) -{ -	/* FIXME: This function must probably be called from the mac80211 -	 * config callback. */ -	return; - -	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); -	//FIXME kill magic -	b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); - -	/*TODO: We might need some stack support here to get the values. */ +	if (b43_using_pio_transfers(dev)) +		b43_pio_tx_resume(dev); +	else +		b43_dma_tx_resume(dev);  } diff --git a/package/b43/src/xmit.h b/package/b43/src/xmit.h index 417650395..0215faf47 100644 --- a/package/b43/src/xmit.h +++ b/package/b43/src/xmit.h @@ -178,7 +178,7 @@ int 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); +		       const struct ieee80211_tx_info *txctl, u16 cookie);  /* Transmit Status */  struct b43_txstatus { @@ -207,25 +207,24 @@ enum {  	B43_TXST_SUPP_ABNACK,	/* Afterburner NACK */  }; -/* Transmit Status as received through DMA/PIO on old chips */ -struct b43_hwtxstatus { -	PAD_BYTES(4); -	__le16 cookie; -	u8 flags; -	u8 count; -	 PAD_BYTES(2); -	__le16 seq; -	u8 phy_stat; -	 PAD_BYTES(1); -} __attribute__ ((__packed__)); -  /* Receive header for v4 firmware. */  struct b43_rxhdr_fw4 {  	__le16 frame_len;	/* Frame length */  	 PAD_BYTES(2);  	__le16 phy_status0;	/* PHY RX Status 0 */ -	__u8 jssi;		/* PHY RX Status 1: JSSI */ -	__u8 sig_qual;		/* PHY RX Status 1: Signal Quality */ +	union { +		/* RSSI for A/B/G-PHYs */ +		struct { +			__u8 jssi;	/* PHY RX Status 1: JSSI */ +			__u8 sig_qual;	/* PHY RX Status 1: Signal Quality */ +		} __attribute__ ((__packed__)); + +		/* RSSI for N-PHYs */ +		struct { +			__s8 power0;	/* PHY RX Status 1: Power 0 */ +			__s8 power1;	/* PHY RX Status 1: Power 1 */ +		} __attribute__ ((__packed__)); +	} __attribute__ ((__packed__));  	__le16 phy_status2;	/* PHY RX Status 2 */  	__le16 phy_status3;	/* PHY RX Status 3 */  	__le32 mac_status;	/* MAC RX status */ @@ -295,25 +294,12 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);  void b43_handle_txstatus(struct b43_wldev *dev,  			 const struct b43_txstatus *status); - -void b43_handle_hwtxstatus(struct b43_wldev *dev, -			   const struct b43_hwtxstatus *hw); +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +			      const struct b43_txstatus *status);  void b43_tx_suspend(struct b43_wldev *dev);  void b43_tx_resume(struct b43_wldev *dev); -#define B43_NR_QOSPARMS		22 -enum { -	B43_QOSPARM_TXOP = 0, -	B43_QOSPARM_CWMIN, -	B43_QOSPARM_CWMAX, -	B43_QOSPARM_CWCUR, -	B43_QOSPARM_AIFS, -	B43_QOSPARM_BSLOTS, -	B43_QOSPARM_REGGAP, -	B43_QOSPARM_STATUS, -}; -void b43_qos_init(struct b43_wldev *dev);  /* Helper functions for converting the key-table index from "firmware-format"   * to "raw-format" and back. The firmware API changed for this at some revision. | 
