Update b43 from compat-wireless-2008-05-26 codebase
SVN-Revision: 11358
This commit is contained in:
parent
e8620fa5aa
commit
b2a1f5e79b
22 changed files with 3081 additions and 1664 deletions
|
@ -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) \
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *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_ring0;
|
||||
struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
|
||||
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;
|
||||
|
||||
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!) */
|
||||
|
|
|
@ -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;
|
||||
expire = time + expire;
|
||||
|
||||
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));
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,104 +959,105 @@ 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;
|
||||
if (b43_using_pio_transfers(dev))
|
||||
return;
|
||||
dma = &dev->dma;
|
||||
|
||||
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;
|
||||
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);
|
||||
|
@ -1051,34 +1065,23 @@ int b43_dma_init(struct b43_wldev *dev)
|
|||
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,28 +1091,7 @@ 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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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,6 +255,12 @@ struct b43_dmaring {
|
|||
int max_used_slots;
|
||||
/* Last time we injected a ring overflow. */
|
||||
unsigned long last_injected_overflow;
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, 0x43,
|
||||
(b43_radio_read16(dev, 0x43) & 0xFFF0)
|
||||
| rfatt->att);
|
||||
b43_radio_write16(dev, txctl_reg,
|
||||
(b43_radio_read16(dev, txctl_reg)
|
||||
& ~txctl_value)
|
||||
| (rfatt_list->list[rfidx].with_padmix ?
|
||||
txctl_value : 0));
|
||||
(b43_radio_read16(dev, txctl_reg) & ~txctl_value)
|
||||
| (rfatt->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 = 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_list->list[bbidx].att);
|
||||
b43_phy_set_baseband_attenuation(dev, bbatt->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));
|
||||
}
|
||||
}
|
||||
|
||||
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 B43_DEBUG
|
||||
static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
|
||||
int i = control->i;
|
||||
int q = control->q;
|
||||
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
|
||||
struct b43_lo_calib *c;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (is_initializing && control->used)
|
||||
goto error;
|
||||
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;
|
||||
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);
|
||||
return c;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
|
||||
{
|
||||
b43_call_for_each_loctl(dev, do_reset_calib);
|
||||
}
|
||||
|
||||
#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);
|
||||
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;
|
||||
|
||||
B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
|
||||
(phy->type != B43_PHYTYPE_G));
|
||||
BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
|
||||
B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
|
||||
|
||||
sav.old_channel = phy->channel;
|
||||
lo_measure_setup(dev, &sav);
|
||||
reset_all_loctl_calibration_states(dev);
|
||||
lo_measure(dev);
|
||||
lo_measure_restore(dev, &sav);
|
||||
power_vector = lo->power_vector;
|
||||
if (!update_all && !power_vector)
|
||||
return; /* Nothing to do. */
|
||||
|
||||
validate_all_loctls(dev);
|
||||
/* Suspend the MAC now to avoid continuous suspend/enable
|
||||
* cycles in the loop. */
|
||||
b43_mac_suspend(dev);
|
||||
|
||||
phy->lo_control->lo_measured = 1;
|
||||
phy->lo_control->rebuild = 0;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
#if B43_DEBUG
|
||||
static void validate_loctl_calibration(struct b43_wldev *dev,
|
||||
struct b43_loctl *loctl,
|
||||
struct b43_rfatt *rfatt,
|
||||
struct b43_bbatt *bbatt)
|
||||
/* 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 (b43_loctl_is_calibrated(loctl))
|
||||
if (!rf->with_padmix)
|
||||
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;
|
||||
}
|
||||
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)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
|
||||
u8 tx_control)
|
||||
{
|
||||
if (tx_control & B43_TXCTL_TXMIX) {
|
||||
if (rf->att < 5)
|
||||
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)
|
||||
{
|
||||
control->used = 0;
|
||||
}
|
||||
|
||||
void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
|
||||
/* Periodic LO maintanance work */
|
||||
void b43_lo_g_maintanance_work(struct b43_wldev *dev)
|
||||
{
|
||||
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;
|
||||
|
||||
b43_call_for_each_loctl(dev, do_mark_unused);
|
||||
lo->rebuild = 1;
|
||||
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?
|
||||
}
|
||||
|
||||
void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
|
||||
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_cleanup(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
|
||||
struct b43_lo_calib *cal, *tmp;
|
||||
|
||||
if (!lo)
|
||||
return;
|
||||
list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
|
||||
list_del(&cal->list);
|
||||
kfree(cal);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
/* 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_ */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,9 +1365,7 @@ 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);
|
||||
} else {
|
||||
b43_lo_g_init(dev);
|
||||
if (has_tx_magnification(phy)) {
|
||||
b43_radio_write16(dev, 0x52,
|
||||
(b43_radio_read16(dev, 0x52) & 0xFF00)
|
||||
|
@ -1561,7 +1390,6 @@ static void b43_phy_initg(struct b43_wldev *dev)
|
|||
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++) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
842
package/b43/src/pio.c
Normal file
842
package/b43/src/pio.c
Normal file
|
@ -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);
|
||||
}
|
216
package/b43/src/pio.h
Normal file
216
package/b43/src/pio.h
Normal file
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
/* Link quality statistics */
|
||||
status.noise = dev->stats.link_noise;
|
||||
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.noise = dev->stats.link_noise;
|
||||
/* the next line looks wrong, but is what mac80211 wants */
|
||||
status.signal = (jssi * 100) / B43_RX_MAX_SSI;
|
||||
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++;
|
||||
}
|
||||
|
||||
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;
|
||||
bool frame_success = 1;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
b43_handle_txstatus(dev, &status);
|
||||
return frame_success;
|
||||
}
|
||||
|
||||
/* Stop any TX operation on the device (suspend the hardware queues) */
|
||||
void b43_tx_suspend(struct b43_wldev *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)
|
||||
{
|
||||
if (b43_using_pio_transfers(dev))
|
||||
b43_pio_tx_resume(dev);
|
||||
else
|
||||
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. */
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue