1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-27 22:21:51 +02:00

Update b43 from compat-wireless-2008-05-26 codebase

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11358 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
noz 2008-06-04 19:47:48 +00:00
parent 38f0bdeb17
commit 18233555f4
22 changed files with 3081 additions and 1664 deletions

View File

@ -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) \

View File

@ -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

View File

@ -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;
/* DMA engines. */
struct b43_dma dma;
union {
/* DMA engines. */
struct b43_dma dma;
/* PIO engines. */
struct b43_pio pio;
};
/* Use b43_using_pio_transfers() to check whether we are using
* DMA or PIO data transfers. */
bool __using_pio_transfers;
/* Various statistics about the physical device. */
struct b43_stats stats;
@ -808,6 +926,22 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
ssb_write32(dev->dev, offset, value);
}
static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
{
#ifdef CONFIG_B43_PIO
return dev->__using_pio_transfers;
#else
return 0;
#endif
}
#ifdef CONFIG_B43_FORCE_PIO
# define B43_FORCE_PIO 1
#else
# define B43_FORCE_PIO 0
#endif
/* Message printing */
void b43info(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
@ -831,22 +965,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; }
# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
#endif
/** Limit a value between two limits */
#ifdef limit_value
# undef limit_value
#endif
#define limit_value(value, min, max) \
({ \
typeof(value) __value = (value); \
typeof(value) __min = (min); \
typeof(value) __max = (max); \
if (__value < __min) \
__value = __min; \
else if (__value > __max) \
__value = __max; \
__value; \
})
/* Convert an integer to a Q5.2 value */
#define INT_TO_Q52(i) ((i) << 2)
/* Convert a Q5.2 value to an integer (precision loss!) */

View File

@ -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;

View File

@ -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,
};

View File

@ -38,6 +38,7 @@
#include <linux/delay.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <asm/div64.h>
/* 32bit DMA ops. */
@ -291,52 +292,6 @@ static inline int request_slot(struct b43_dmaring *ring)
return slot;
}
/* Mac80211-queue to b43-ring mapping */
static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
int queue_priority)
{
struct b43_dmaring *ring;
/*FIXME: For now we always run on TX-ring-1 */
return dev->dma.tx_ring1;
/* 0 = highest priority */
switch (queue_priority) {
default:
B43_WARN_ON(1);
/* fallthrough */
case 0:
ring = dev->dma.tx_ring3;
break;
case 1:
ring = dev->dma.tx_ring2;
break;
case 2:
ring = dev->dma.tx_ring1;
break;
case 3:
ring = dev->dma.tx_ring0;
break;
}
return ring;
}
/* b43-ring to mac80211-queue mapping */
static inline int txring_to_priority(struct b43_dmaring *ring)
{
static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
unsigned int index;
/*FIXME: have only one queue, for now */
return 0;
index = ring->index;
if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
index = 0;
return idx_to_prio[index];
}
static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
{
static const u16 map64[] = {
@ -373,10 +328,10 @@ static inline
dma_addr_t dmaaddr;
if (tx) {
dmaaddr = dma_map_single(ring->dev->dev->dev,
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_TO_DEVICE);
} else {
dmaaddr = dma_map_single(ring->dev->dev->dev,
dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len, DMA_FROM_DEVICE);
}
@ -388,9 +343,10 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE);
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_TO_DEVICE);
} else {
dma_unmap_single(ring->dev->dev->dev,
dma_unmap_single(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
}
@ -400,7 +356,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_cpu(ring->dev->dev->dev,
dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@ -409,7 +365,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
dma_sync_single_for_device(ring->dev->dev->dev,
dma_sync_single_for_device(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@ -425,7 +381,7 @@ static inline
static int alloc_ringmemory(struct b43_dmaring *ring)
{
struct device *dev = ring->dev->dev->dev;
struct device *dma_dev = ring->dev->dev->dma_dev;
gfp_t flags = GFP_KERNEL;
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
@ -439,7 +395,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
@ -452,9 +408,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
static void free_ringmemory(struct b43_dmaring *ring)
{
struct device *dev = ring->dev->dev->dev;
struct device *dma_dev = ring->dev->dev->dma_dev;
dma_free_coherent(dev, B43_DMA_RINGMEMSIZE,
dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase);
}
@ -560,7 +516,7 @@ static int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base,
/* Check if a DMA mapping address is invalid. */
static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr,
size_t buffersize)
size_t buffersize, bool dma_to_device)
{
if (unlikely(dma_mapping_error(addr)))
return 1;
@ -568,11 +524,11 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
switch (ring->type) {
case B43_DMA_30BIT:
if ((u64)addr + buffersize > (1ULL << 30))
return 1;
goto address_error;
break;
case B43_DMA_32BIT:
if ((u64)addr + buffersize > (1ULL << 32))
return 1;
goto address_error;
break;
case B43_DMA_64BIT:
/* Currently we can't have addresses beyond
@ -582,6 +538,12 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
/* The address is OK. */
return 0;
address_error:
/* We can't support this address. Unmap it again. */
unmap_descbuffer(ring, addr, buffersize, dma_to_device);
return 1;
}
static int setup_rx_descbuffer(struct b43_dmaring *ring,
@ -589,7 +551,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
{
struct b43_rxhdr_fw4 *rxhdr;
struct b43_hwtxstatus *txstat;
dma_addr_t dmaaddr;
struct sk_buff *skb;
@ -599,7 +560,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
if (unlikely(!skb))
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
/* ugh. try to realloc in zone_dma */
gfp_flags |= GFP_DMA;
@ -612,7 +573,8 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
ring->rx_buffersize, 0);
}
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) {
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
b43err(ring->dev->wl, "RX DMA buffer allocation failed\n");
dev_kfree_skb_any(skb);
return -EIO;
}
@ -624,8 +586,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
rxhdr->frame_len = 0;
txstat = (struct b43_hwtxstatus *)(skb->data);
txstat->cookie = 0;
return 0;
}
@ -814,6 +774,18 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
return DMA_30BIT_MASK;
}
static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask)
{
if (dmamask == DMA_30BIT_MASK)
return B43_DMA_30BIT;
if (dmamask == DMA_32BIT_MASK)
return B43_DMA_32BIT;
if (dmamask == DMA_64BIT_MASK)
return B43_DMA_64BIT;
B43_WARN_ON(1);
return B43_DMA_30BIT;
}
/* Main initialization function. */
static
struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
@ -847,12 +819,13 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
dma_test = dma_map_single(dev->dev->dev,
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev))) {
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
/* ugh realloc */
kfree(ring->txhdr_cache);
ring->txhdr_cache = kcalloc(nr_slots,
@ -861,17 +834,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
dma_test = dma_map_single(dev->dev->dev,
dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev)))
b43_txhdr_size(dev), 1)) {
b43err(dev->wl,
"TXHDR DMA allocation failed\n");
goto err_kfree_txhdr_cache;
}
}
dma_unmap_single(dev->dev->dev,
dma_unmap_single(dev->dev->dma_dev,
dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE);
}
@ -924,16 +901,52 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto out;
}
#define divide(a, b) ({ \
typeof(a) __a = a; \
do_div(__a, b); \
__a; \
})
#define modulo(a, b) ({ \
typeof(a) __a = a; \
do_div(__a, b); \
})
/* Main cleanup function. */
static void b43_destroy_dmaring(struct b43_dmaring *ring)
static void b43_destroy_dmaring(struct b43_dmaring *ring,
const char *ringname)
{
if (!ring)
return;
b43dbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots: %d/%d\n",
(unsigned int)(ring->type),
ring->mmio_base,
(ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
#ifdef CONFIG_B43_DEBUG
{
/* Print some statistics. */
u64 failed_packets = ring->nr_failed_tx_packets;
u64 succeed_packets = ring->nr_succeed_tx_packets;
u64 nr_packets = failed_packets + succeed_packets;
u64 permille_failed = 0, average_tries = 0;
if (nr_packets)
permille_failed = divide(failed_packets * 1000, nr_packets);
if (nr_packets)
average_tries = divide(ring->nr_total_packet_tries * 100, nr_packets);
b43dbg(ring->dev->wl, "DMA-%u %s: "
"Used slots %d/%d, Failed frames %llu/%llu = %llu.%01llu%%, "
"Average tries %llu.%02llu\n",
(unsigned int)(ring->type), ringname,
ring->max_used_slots,
ring->nr_slots,
(unsigned long long)failed_packets,
(unsigned long long)nr_packets,
(unsigned long long)divide(permille_failed, 10),
(unsigned long long)modulo(permille_failed, 10),
(unsigned long long)divide(average_tries, 100),
(unsigned long long)modulo(average_tries, 100));
}
#endif /* DEBUG */
/* Device IRQs are disabled prior entering this function,
* so no need to take care of concurrency with rx handler stuff.
*/
@ -946,139 +959,129 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
kfree(ring);
}
#define destroy_ring(dma, ring) do { \
b43_destroy_dmaring((dma)->ring, __stringify(ring)); \
(dma)->ring = NULL; \
} while (0)
void b43_dma_free(struct b43_wldev *dev)
{
struct b43_dma *dma = &dev->dma;
struct b43_dma *dma;
b43_destroy_dmaring(dma->rx_ring3);
dma->rx_ring3 = NULL;
b43_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL;
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);
err = 0;
out:
out:
return err;
err_destroy_rx0:
b43_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL;
err_destroy_tx5:
b43_destroy_dmaring(dma->tx_ring5);
dma->tx_ring5 = NULL;
err_destroy_tx4:
b43_destroy_dmaring(dma->tx_ring4);
dma->tx_ring4 = NULL;
err_destroy_tx3:
b43_destroy_dmaring(dma->tx_ring3);
dma->tx_ring3 = NULL;
err_destroy_tx2:
b43_destroy_dmaring(dma->tx_ring2);
dma->tx_ring2 = NULL;
err_destroy_tx1:
b43_destroy_dmaring(dma->tx_ring1);
dma->tx_ring1 = NULL;
err_destroy_tx0:
b43_destroy_dmaring(dma->tx_ring0);
dma->tx_ring0 = NULL;
goto out;
err_destroy_mcast:
destroy_ring(dma, tx_ring_mcast);
err_destroy_vo:
destroy_ring(dma, tx_ring_AC_VO);
err_destroy_vi:
destroy_ring(dma, tx_ring_AC_VI);
err_destroy_be:
destroy_ring(dma, tx_ring_AC_BE);
err_destroy_bk:
destroy_ring(dma, tx_ring_AC_BK);
return err;
}
/* Generate a cookie for the TX header. */
static u16 generate_cookie(struct b43_dmaring *ring, int slot)
{
u16 cookie = 0x1000;
u16 cookie;
/* Use the upper 4 bits of the cookie as
* DMA controller ID and store the slot number
@ -1088,30 +1091,9 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
* It can also not be 0xFFFF because that is special
* for multicast frames.
*/
switch (ring->index) {
case 0:
cookie = 0x1000;
break;
case 1:
cookie = 0x2000;
break;
case 2:
cookie = 0x3000;
break;
case 3:
cookie = 0x4000;
break;
case 4:
cookie = 0x5000;
break;
case 5:
cookie = 0x6000;
break;
default:
B43_WARN_ON(1);
}
cookie = (((u16)ring->index + 1) << 12);
B43_WARN_ON(slot & ~0x0FFF);
cookie |= (u16) slot;
cookie |= (u16)slot;
return cookie;
}
@ -1125,22 +1107,19 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
switch (cookie & 0xF000) {
case 0x1000:
ring = dma->tx_ring0;
ring = dma->tx_ring_AC_BK;
break;
case 0x2000:
ring = dma->tx_ring1;
ring = dma->tx_ring_AC_BE;
break;
case 0x3000:
ring = dma->tx_ring2;
ring = dma->tx_ring_AC_VI;
break;
case 0x4000:
ring = dma->tx_ring3;
ring = dma->tx_ring_AC_VO;
break;
case 0x5000:
ring = dma->tx_ring4;
break;
case 0x6000:
ring = dma->tx_ring5;
ring = dma->tx_ring_mcast;
break;
default:
B43_WARN_ON(1);
@ -1152,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
}
static int dma_tx_fragment(struct b43_dmaring *ring,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
struct sk_buff *skb)
{
const struct b43_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header;
int slot, old_top_slot, old_used_slots;
int err;
@ -1167,7 +1146,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
size_t hdrsize = b43_txhdr_size(ring->dev);
#define SLOTS_PER_PACKET 2
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
old_top_slot = ring->current_slot;
old_used_slots = ring->used_slots;
@ -1180,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
header = &(ring->txhdr_cache[slot * hdrsize]);
cookie = generate_cookie(ring, slot);
err = b43_generate_txhdr(ring->dev, header,
skb->data, skb->len, ctl, cookie);
skb->data, skb->len, info, cookie);
if (unlikely(err)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
@ -1189,7 +1167,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
hdrsize, 1);
if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize)) {
if (b43_dma_mapping_error(ring, meta_hdr->dmaaddr, hdrsize, 1)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
return -EIO;
@ -1202,13 +1180,12 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
desc = ops->idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta));
memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb;
meta->is_last_fragment = 1;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb) {
ring->current_slot = old_top_slot;
@ -1222,7 +1199,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
skb = bounce_skb;
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len)) {
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -EIO;
@ -1232,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */
b43_shm_write16(ring->dev, B43_SHM_SHARED,
@ -1272,29 +1249,56 @@ static inline int should_inject_overflow(struct b43_dmaring *ring)
return 0;
}
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
/* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */
static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
u8 queue_prio)
{
struct b43_dmaring *ring;
if (b43_modparam_qos) {
/* 0 = highest priority */
switch (queue_prio) {
default:
B43_WARN_ON(1);
/* fallthrough */
case 0:
ring = dev->dma.tx_ring_AC_VO;
break;
case 1:
ring = dev->dma.tx_ring_AC_VI;
break;
case 2:
ring = dev->dma.tx_ring_AC_BE;
break;
case 3:
ring = dev->dma.tx_ring_AC_BK;
break;
}
} else
ring = dev->dma.tx_ring_AC_BE;
return ring;
}
int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
{
struct b43_dmaring *ring;
struct ieee80211_hdr *hdr;
int err = 0;
unsigned long flags;
if (unlikely(skb->len < 2 + 2 + 6)) {
/* Too short, this can't be a valid frame. */
return -EINVAL;
}
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data;
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast ring will be sent after the DTIM */
ring = dev->dma.tx_ring4;
ring = dev->dma.tx_ring_mcast;
/* Set the more-data bit. Ucode will clear it on
* the last frame for us. */
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else {
/* Decide by priority where to put this frame. */
ring = priority_to_txring(dev, ctl->queue);
ring = select_ring_by_priority(
dev, skb_get_queue_mapping(skb));
}
spin_lock_irqsave(&ring->lock, flags);
@ -1309,7 +1313,12 @@ int b43_dma_tx(struct b43_wldev *dev,
* That would be a mac80211 bug. */
B43_WARN_ON(ring->stopped);
err = dma_tx_fragment(ring, skb, ctl);
/* Assign the queue number to the ring (if not already done before)
* so TX status handling can use it. The queue to ring mapping is
* static, so we don't need to store it per frame. */
ring->queue_prio = skb_get_queue_mapping(skb);
err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
@ -1325,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev,
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
ring->stopped = 1;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@ -1337,6 +1346,7 @@ out_unlock:
return err;
}
/* Called with IRQs disabled. */
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
@ -1345,12 +1355,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
struct b43_dmadesc_generic *desc;
struct b43_dmadesc_meta *meta;
int slot;
bool frame_succeed;
ring = parse_cookie(dev, status->cookie, &slot);
if (unlikely(!ring))
return;
B43_WARN_ON(!irqs_disabled());
spin_lock(&ring->lock);
spin_lock(&ring->lock); /* IRQs are already disabled. */
B43_WARN_ON(!ring->tx);
ops = ring->ops;
@ -1366,25 +1377,28 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
b43_txhdr_size(dev), 1);
if (meta->is_last_fragment) {
B43_WARN_ON(!meta->skb);
/* Call back to inform the ieee80211 subsystem about the
* status of the transmission.
* Some fields of txstat are already filled in dma_tx().
struct ieee80211_tx_info *info;
BUG_ON(!meta->skb);
info = IEEE80211_SKB_CB(meta->skb);
memset(&info->status, 0, sizeof(info->status));
/*
* Call back to inform the ieee80211 subsystem about
* the status of the transmission.
*/
if (status->acked) {
meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
} else {
if (!(meta->txstat.control.flags
& IEEE80211_TXCTL_NO_ACK))
meta->txstat.excessive_retries = 1;
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
meta->txstat.retry_count = 0;
} else
meta->txstat.retry_count = status->frame_count - 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
&(meta->txstat));
frame_succeed = b43_fill_txstatus_report(info, status);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
else
ring->nr_failed_tx_packets++;
ring->nr_total_packet_tries += status->frame_count;
#endif /* DEBUG */
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
/* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
} else {
@ -1404,7 +1418,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
dev->stats.last_tx = jiffies;
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
ring->stopped = 0;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
@ -1419,18 +1433,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
{
const int nr_queues = dev->wl->hw->queues;
struct b43_dmaring *ring;
struct ieee80211_tx_queue_stats_data *data;
unsigned long flags;
int i;
for (i = 0; i < nr_queues; i++) {
data = &(stats->data[i]);
ring = priority_to_txring(dev, i);
ring = select_ring_by_priority(dev, i);
spin_lock_irqsave(&ring->lock, flags);
data->len = ring->used_slots / SLOTS_PER_PACKET;
data->limit = ring->nr_slots / SLOTS_PER_PACKET;
data->count = ring->nr_tx_packets;
stats[i].len = ring->used_slots / SLOTS_PER_PACKET;
stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET;
stats[i].count = ring->nr_tx_packets;
spin_unlock_irqrestore(&ring->lock, flags);
}
}
@ -1451,25 +1463,6 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
skb = meta->skb;
if (ring->index == 3) {
/* We received an xmit status. */
struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
int i = 0;
while (hw->cookie == 0) {
if (i > 100)
break;
i++;
udelay(2);
barrier();
}
b43_handle_hwtxstatus(ring->dev, hw);
/* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
return;
}
rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
len = le16_to_cpu(rxhdr->frame_len);
if (len == 0) {
@ -1526,7 +1519,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
skb_pull(skb, ring->frameoffset);
b43_rx(ring->dev, skb, rxhdr);
drop:
drop:
return;
}
@ -1572,21 +1565,55 @@ static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)
void b43_dma_tx_suspend(struct b43_wldev *dev)
{
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BK);
b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_BE);
b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VI);
b43_dma_tx_suspend_ring(dev->dma.tx_ring_AC_VO);
b43_dma_tx_suspend_ring(dev->dma.tx_ring_mcast);
}
void b43_dma_tx_resume(struct b43_wldev *dev)
{
b43_dma_tx_resume_ring(dev->dma.tx_ring5);
b43_dma_tx_resume_ring(dev->dma.tx_ring4);
b43_dma_tx_resume_ring(dev->dma.tx_ring3);
b43_dma_tx_resume_ring(dev->dma.tx_ring2);
b43_dma_tx_resume_ring(dev->dma.tx_ring1);
b43_dma_tx_resume_ring(dev->dma.tx_ring0);
b43_dma_tx_resume_ring(dev->dma.tx_ring_mcast);
b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VO);
b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_VI);
b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BE);
b43_dma_tx_resume_ring(dev->dma.tx_ring_AC_BK);
b43_power_saving_ctl_bits(dev, 0);
}
#ifdef CONFIG_B43_PIO
static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type,
u16 mmio_base, bool enable)
{
u32 ctl;
if (type == B43_DMA_64BIT) {
ctl = b43_read32(dev, mmio_base + B43_DMA64_RXCTL);
ctl &= ~B43_DMA64_RXDIRECTFIFO;
if (enable)
ctl |= B43_DMA64_RXDIRECTFIFO;
b43_write32(dev, mmio_base + B43_DMA64_RXCTL, ctl);
} else {
ctl = b43_read32(dev, mmio_base + B43_DMA32_RXCTL);
ctl &= ~B43_DMA32_RXDIRECTFIFO;
if (enable)
ctl |= B43_DMA32_RXDIRECTFIFO;
b43_write32(dev, mmio_base + B43_DMA32_RXCTL, ctl);
}
}
/* Enable/Disable Direct FIFO Receive Mode (PIO) on a RX engine.
* This is called from PIO code, so DMA structures are not available. */
void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
unsigned int engine_index, bool enable)
{
enum b43_dmatype type;
u16 mmio_base;
type = dma_mask_to_engine_type(supported_dma_mask(dev));
mmio_base = b43_dmacontroller_base(type, engine_index);
direct_fifo_rx(dev, type, mmio_base, enable);
}
#endif /* CONFIG_B43_PIO */

View File

@ -181,7 +181,6 @@ struct b43_dmadesc_meta {
dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment;
struct ieee80211_tx_status txstat;
};
struct b43_dmaring;
@ -245,6 +244,9 @@ struct b43_dmaring {
enum b43_dmatype type;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
/* The QOS priority assigned to this ring. Only used for TX rings.
* This is the mac80211 "queue" value. */
u8 queue_prio;
/* Lock, only used for TX. */
spinlock_t lock;
struct b43_wldev *dev;
@ -253,7 +255,13 @@ struct b43_dmaring {
int max_used_slots;
/* Last time we injected a ring overflow. */
unsigned long last_injected_overflow;
#endif /* CONFIG_B43_DEBUG */
/* Statistics: Number of successfully transmitted packets */
u64 nr_succeed_tx_packets;
/* Statistics: Number of failed TX packets */
u64 nr_failed_tx_packets;
/* Statistics: Total number of TX plus all retries. */
u64 nr_total_packet_tries;
#endif /* CONFIG_B43_DEBUG */
};
static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
@ -276,10 +284,13 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats);
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl);
struct sk_buff *skb);
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_dma_rx(struct b43_dmaring *ring);
void b43_dma_direct_fifo_rx(struct b43_wldev *dev,
unsigned int engine_index, bool enable);
#endif /* B43_DMA_H_ */

View File

@ -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);

View File

@ -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->att);
b43_radio_write16(dev, txctl_reg,
(b43_radio_read16(dev, txctl_reg) & ~txctl_value)
| (rfatt->with_padmix) ? txctl_value : 0);
b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
& 0xFFF0) |
rfatt_list->list[rfidx].att);
b43_radio_write16(dev, txctl_reg,
(b43_radio_read16(dev, txctl_reg)
& ~txctl_value)
| (rfatt_list->list[rfidx].with_padmix ?
txctl_value : 0));
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));
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;
b43_phy_set_baseband_attenuation(dev, bbatt->att);
lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
max_rx_gain = rfatt_list->list[rfidx].att * 2;
max_rx_gain += bbatt_list->list[bbidx].att / 2;
if (rfatt_list->list[rfidx].with_padmix)
max_rx_gain -= pad_mix_gain;
if (has_loopback_gain(phy))
max_rx_gain += phy->max_lb_gain;
lo_measure_gain_values(dev, max_rx_gain,
has_loopback_gain(phy));
lo_measure_restore(dev, &saved_regs);
b43_mac_enable(dev);
b43_phy_set_baseband_attenuation(dev,
bbatt_list->list[bbidx].att);
lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
if (phy->type == B43_PHYTYPE_B) {
loctl.i++;
loctl.q++;
}
b43_loctl_set_calibrated(&loctl, 1);
memcpy(ploctl, &loctl, sizeof(loctl));
}
if (b43_debug(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)
{
const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
int i = control->i;
int q = control->q;
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;
}
cal = kmalloc(sizeof(*cal), GFP_KERNEL);
if (!cal) {
b43warn(dev->wl, "LO calib: out of memory\n");
return NULL;
}
if (is_initializing && control->used)
goto error;
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;
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 cal;
}
static void validate_all_loctls(struct b43_wldev *dev)
/* Get a calibrated LO setting for the given attenuation values.
* Might return a NULL pointer under OOM! */
static
struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt)
{
b43_call_for_each_loctl(dev, do_validate_loctl);
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
struct b43_lo_calib *c;
c = b43_find_lo_calib(lo, bbatt, rfatt);
if (c)
return c;
/* Not in the list of calibrated LO settings.
* Calibrate it now. */
c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
if (!c)
return NULL;
list_add(&c->list, &lo->calib_list);
return c;
}
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 B43_DEBUG
static void validate_loctl_calibration(struct b43_wldev *dev,
struct b43_loctl *loctl,
struct b43_rfatt *rfatt,
struct b43_bbatt *bbatt)
{
if (b43_loctl_is_calibrated(loctl))
return;
if (!dev->phy.lo_control->lo_measured) {
/* On init we set the attenuation values before we
* calibrated the LO. I guess that's OK. */
return;
if (!update_all && !(power_vector & (((u64)1ULL) << i)))
continue;
/* Update the table entry for this power_vector bit.
* The table rows are RFatt entries and columns are BBatt. */
bb_offset = i / lo->rfatt_list.len;
rf_offset = i % lo->rfatt_list.len;
bbatt = &(lo->bbatt_list.list[bb_offset]);
rfatt = &(lo->rfatt_list.list[rf_offset]);
cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
if (!cal) {
b43warn(dev->wl, "LO: Could not "
"calibrate DC table entry\n");
continue;
}
/*FIXME: Is Q really in the low nibble? */
val = (u8)(cal->ctl.q);
val |= ((u8)(cal->ctl.i)) << 4;
kfree(cal);
/* Get the index into the hardware DC LT. */
idx = i / 2;
/* Change the table in memory. */
if (i % 2) {
/* Change the high byte. */
lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
| ((val & 0x00FF) << 8);
} else {
/* Change the low byte. */
lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
| (val & 0x00FF);
}
table_changed = 1;
}
b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
"control pair: rfatt=%u,%spadmix bbatt=%u\n",
rfatt->att,
(rfatt->with_padmix) ? "" : "no-",
bbatt->att);
}
#else
static inline void validate_loctl_calibration(struct b43_wldev *dev,
struct b43_loctl *loctl,
struct b43_rfatt *rfatt,
struct b43_bbatt *bbatt)
{
}
#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)
rf->att = 4;
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);
}
/* 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 (!rf->with_padmix)
return;
if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
rf->att = 4;
}
void b43_lo_g_adjust(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_lo_calib *cal;
struct b43_rfatt rf;
struct b43_loctl *loctl;
memcpy(&rf, &phy->rfatt, sizeof(rf));
fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
b43_lo_fixup_rfatt(&rf);
loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
b43_lo_write(dev, loctl);
cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
if (!cal)
return;
b43_lo_write(dev, &cal->ctl);
}
void b43_lo_g_adjust_to(struct b43_wldev *dev,
@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
{
struct b43_rfatt rf;
struct b43_bbatt bb;
struct b43_loctl *loctl;
struct b43_lo_calib *cal;
memset(&rf, 0, sizeof(rf));
memset(&bb, 0, sizeof(bb));
rf.att = rfatt;
bb.att = bbatt;
fixup_rfatt_for_txcontrol(&rf, tx_control);
loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
validate_loctl_calibration(dev, loctl, &rf, &bb);
b43_lo_write(dev, loctl);
b43_lo_fixup_rfatt(&rf);
cal = b43_get_calib_lo_settings(dev, &bb, &rf);
if (!cal)
return;
b43_lo_write(dev, &cal->ctl);
}
static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
{
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?
}
if (hwpctl)
return;
/* Search for expired LO settings. Remove them.
* Recalibrate the current setting, if expired. */
expire = now - B43_LO_CALIB_EXPIRE;
list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
if (!time_before(cal->calib_time, expire))
continue;
/* This item expired. */
if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
B43_WARN_ON(current_item_expired);
current_item_expired = 1;
}
if (b43_debug(dev, B43_DBG_LO)) {
b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
"I=%d, Q=%d expired\n",
cal->bbatt.att, cal->rfatt.att,
cal->rfatt.with_padmix,
cal->ctl.i, cal->ctl.q);
}
list_del(&cal->list);
kfree(cal);
}
if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
/* Recalibrate currently used LO setting. */
if (b43_debug(dev, B43_DBG_LO))
b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
if (cal) {
list_add(&cal->list, &lo->calib_list);
b43_lo_write(dev, &cal->ctl);
} else
b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
}
}
void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
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);
}
}

View File

@ -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

View File

@ -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_ */

View File

@ -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);

View File

@ -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_ */

View File

@ -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);

View File

@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/bitrev.h>
#include "b43.h"
#include "phy.h"
@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = {
72, 84,
};
#define bitrev4(tmp) (bitrev8(tmp) >> 4)
static void b43_phy_initg(struct b43_wldev *dev);
/* Reverse the bits of a 4bit value.
* Example: 1101 is flipped 1011
*/
static u16 flip_4bit(u16 value)
{
u16 flipped = 0x0000;
B43_WARN_ON(value & ~0x000F);
flipped |= (value & 0x0001) << 3;
flipped |= (value & 0x0002) << 1;
flipped |= (value & 0x0004) >> 1;
flipped |= (value & 0x0008) >> 3;
return flipped;
}
static void generate_rfatt_list(struct b43_wldev *dev,
struct b43_rfatt_list *list)
{
@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
{.att = 9,.with_padmix = 1,},
};
if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
(phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
if (!b43_has_hardware_pctl(phy)) {
/* Software pctl */
list->list = rfatt_0;
list->len = ARRAY_SIZE(rfatt_0);
@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
/* Hardware pctl */
list->list = rfatt_1;
list->len = ARRAY_SIZE(rfatt_1);
list->min_val = 2;
list->min_val = 0;
list->max_val = 14;
return;
}
@ -346,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev,
/* Save the values for later */
phy->tx_control = tx_control;
memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
@ -559,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
u16 tmp;
u8 rf, bb;
if (!lo->lo_measured) {
b43_phy_write(dev, 0x3FF, 0);
return;
}
for (rf = 0; rf < lo->rfatt_list.len; rf++) {
for (bb = 0; bb < lo->bbatt_list.len; bb++) {
if (nr_written >= 0x40)
@ -581,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
}
}
/* GPHY_DC_Lookup_Table */
void b43_gphy_dc_lt_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
struct b43_loctl *loctl0;
struct b43_loctl *loctl1;
int i;
int rf_offset, bb_offset;
u16 tmp;
for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
rf_offset = i / lo->rfatt_list.len;
bb_offset = i % lo->rfatt_list.len;
loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
&lo->bbatt_list.list[bb_offset]);
if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
rf_offset = (i + 1) / lo->rfatt_list.len;
bb_offset = (i + 1) % lo->rfatt_list.len;
loctl1 =
b43_get_lo_g_ctl(dev,
&lo->rfatt_list.list[rf_offset],
&lo->bbatt_list.list[bb_offset]);
} else
loctl1 = loctl0;
tmp = ((u16) loctl0->q & 0xF);
tmp |= ((u16) loctl0->i & 0xF) << 4;
tmp |= ((u16) loctl1->q & 0xF) << 8;
tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME?
b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
}
}
static void hardware_pctl_init_aphy(struct b43_wldev *dev)
{
//TODO
@ -643,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev)
b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
& 0xFFBF);
b43_gphy_dc_lt_init(dev);
b43_gphy_dc_lt_init(dev, 1);
}
/* HardwarePowerControl init for A and G PHY */
@ -860,7 +804,7 @@ static void b43_phy_ww(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_OFDM(0xBB),
(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
b43_phy_write(dev, B43_PHY_OFDM61,
(b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
(b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
b43_phy_write(dev, B43_PHY_OFDM(0x13),
(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
b43_phy_write(dev, B43_PHY_OFDM(0x14),
@ -931,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev)
}
}
static void b43_phy_initb2(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 offset, val;
b43_write16(dev, 0x03EC, 0x3F22);
b43_phy_write(dev, 0x0020, 0x301C);
b43_phy_write(dev, 0x0026, 0x0000);
b43_phy_write(dev, 0x0030, 0x00C6);
b43_phy_write(dev, 0x0088, 0x3E00);
val = 0x3C3D;
for (offset = 0x0089; offset < 0x00A7; offset++) {
b43_phy_write(dev, offset, val);
val -= 0x0202;
}
b43_phy_write(dev, 0x03E4, 0x3000);
b43_radio_selectchannel(dev, phy->channel, 0);
if (phy->radio_ver != 0x2050) {
b43_radio_write16(dev, 0x0075, 0x0080);
b43_radio_write16(dev, 0x0079, 0x0081);
}
b43_radio_write16(dev, 0x0050, 0x0020);
b43_radio_write16(dev, 0x0050, 0x0023);
if (phy->radio_ver == 0x2050) {
b43_radio_write16(dev, 0x0050, 0x0020);
b43_radio_write16(dev, 0x005A, 0x0070);
b43_radio_write16(dev, 0x005B, 0x007B);
b43_radio_write16(dev, 0x005C, 0x00B0);
b43_radio_write16(dev, 0x007A, 0x000F);
b43_phy_write(dev, 0x0038, 0x0677);
b43_radio_init2050(dev);
}
b43_phy_write(dev, 0x0014, 0x0080);
b43_phy_write(dev, 0x0032, 0x00CA);
b43_phy_write(dev, 0x0032, 0x00CC);
b43_phy_write(dev, 0x0035, 0x07C2);
b43_lo_b_measure(dev);
b43_phy_write(dev, 0x0026, 0xCC00);
if (phy->radio_ver != 0x2050)
b43_phy_write(dev, 0x0026, 0xCE00);
b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
b43_phy_write(dev, 0x002A, 0x88A3);
if (phy->radio_ver != 0x2050)
b43_phy_write(dev, 0x002A, 0x88C2);
b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
b43_phy_init_pctl(dev);
}
static void b43_phy_initb4(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 offset, val;
b43_write16(dev, 0x03EC, 0x3F22);
b43_phy_write(dev, 0x0020, 0x301C);
b43_phy_write(dev, 0x0026, 0x0000);
b43_phy_write(dev, 0x0030, 0x00C6);
b43_phy_write(dev, 0x0088, 0x3E00);
val = 0x3C3D;
for (offset = 0x0089; offset < 0x00A7; offset++) {
b43_phy_write(dev, offset, val);
val -= 0x0202;
}
b43_phy_write(dev, 0x03E4, 0x3000);
b43_radio_selectchannel(dev, phy->channel, 0);
if (phy->radio_ver != 0x2050) {
b43_radio_write16(dev, 0x0075, 0x0080);
b43_radio_write16(dev, 0x0079, 0x0081);
}
b43_radio_write16(dev, 0x0050, 0x0020);
b43_radio_write16(dev, 0x0050, 0x0023);
if (phy->radio_ver == 0x2050) {
b43_radio_write16(dev, 0x0050, 0x0020);
b43_radio_write16(dev, 0x005A, 0x0070);
b43_radio_write16(dev, 0x005B, 0x007B);
b43_radio_write16(dev, 0x005C, 0x00B0);
b43_radio_write16(dev, 0x007A, 0x000F);
b43_phy_write(dev, 0x0038, 0x0677);
b43_radio_init2050(dev);
}
b43_phy_write(dev, 0x0014, 0x0080);
b43_phy_write(dev, 0x0032, 0x00CA);
if (phy->radio_ver == 0x2050)
b43_phy_write(dev, 0x0032, 0x00E0);
b43_phy_write(dev, 0x0035, 0x07C2);
b43_lo_b_measure(dev);
b43_phy_write(dev, 0x0026, 0xCC00);
if (phy->radio_ver == 0x2050)
b43_phy_write(dev, 0x0026, 0xCE00);
b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
b43_phy_write(dev, 0x002A, 0x88A3);
if (phy->radio_ver == 0x2050)
b43_phy_write(dev, 0x002A, 0x88C2);
b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
b43_calc_nrssi_slope(dev);
b43_calc_nrssi_threshold(dev);
}
b43_phy_init_pctl(dev);
}
static void b43_phy_initb5(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
@ -1259,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev)
b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
| 0x0004);
}
if (phy->type == B43_PHYTYPE_B) {
b43_write16(dev, 0x03E6, 0x8140);
b43_phy_write(dev, 0x0016, 0x0410);
b43_phy_write(dev, 0x0017, 0x0820);
b43_phy_write(dev, 0x0062, 0x0007);
b43_radio_init2050(dev);
b43_lo_g_measure(dev);
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
b43_calc_nrssi_slope(dev);
b43_calc_nrssi_threshold(dev);
}
b43_phy_init_pctl(dev);
} else if (phy->type == B43_PHYTYPE_G)
if (phy->type == B43_PHYTYPE_B)
B43_WARN_ON(1);
else if (phy->type == B43_PHYTYPE_G)
b43_write16(dev, 0x03E6, 0x0);
}
@ -1534,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev)
else
b43_radio_write16(dev, 0x0078, phy->initval);
}
if (phy->lo_control->tx_bias == 0xFF) {
b43_lo_g_measure(dev);
b43_lo_g_init(dev);
if (has_tx_magnification(phy)) {
b43_radio_write16(dev, 0x52,
(b43_radio_read16(dev, 0x52) & 0xFF00)
| phy->lo_control->tx_bias | phy->
lo_control->tx_magn);
} else {
if (has_tx_magnification(phy)) {
b43_radio_write16(dev, 0x52,
(b43_radio_read16(dev, 0x52) & 0xFF00)
| phy->lo_control->tx_bias | phy->
lo_control->tx_magn);
} else {
b43_radio_write16(dev, 0x52,
(b43_radio_read16(dev, 0x52) & 0xFFF0)
| phy->lo_control->tx_bias);
}
if (phy->rev >= 6) {
b43_phy_write(dev, B43_PHY_CCK(0x36),
(b43_phy_read(dev, B43_PHY_CCK(0x36))
& 0x0FFF) | (phy->lo_control->
tx_bias << 12));
}
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
else
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
if (phy->rev < 2)
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
else
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
b43_radio_write16(dev, 0x52,
(b43_radio_read16(dev, 0x52) & 0xFFF0)
| phy->lo_control->tx_bias);
}
if (phy->rev >= 6) {
b43_phy_write(dev, B43_PHY_CCK(0x36),
(b43_phy_read(dev, B43_PHY_CCK(0x36))
& 0x0FFF) | (phy->lo_control->
tx_bias << 12));
}
if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
else
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
if (phy->rev < 2)
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
else
b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
if (phy->gmode || phy->rev >= 2) {
b43_lo_g_adjust(dev);
b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
@ -1572,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
* the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver.
* Essentially, what we do here is resetting all NRSSI LT
* entries to -32 (see the limit_value() in nrssi_hw_update())
* entries to -32 (see the clamp_val() in nrssi_hw_update())
*/
b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
b43_calc_nrssi_threshold(dev);
@ -1634,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
switch (phy->type) {
case B43_PHYTYPE_A:
tmp += 0x80;
tmp = limit_value(tmp, 0x00, 0xFF);
tmp = clamp_val(tmp, 0x00, 0xFF);
dbm = phy->tssi2dbm[tmp];
//TODO: There's a FIXME on the specs
break;
case B43_PHYTYPE_B:
case B43_PHYTYPE_G:
tmp = limit_value(tmp, 0x00, 0x3F);
tmp = clamp_val(tmp, 0x00, 0x3F);
dbm = phy->tssi2dbm[tmp];
break;
default:
@ -1699,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
break;
}
*_rfatt = limit_value(rfatt, rf_min, rf_max);
*_bbatt = limit_value(bbatt, bb_min, bb_max);
*_rfatt = clamp_val(rfatt, rf_min, rf_max);
*_bbatt = clamp_val(bbatt, bb_min, bb_max);
}
/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
@ -1795,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
/* Get desired power (in Q5.2) */
desired_pwr = INT_TO_Q52(phy->power_level);
/* And limit it. max_pwr already is Q5.2 */
desired_pwr = limit_value(desired_pwr, 0, max_pwr);
desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
b43dbg(dev->wl,
"Current TX power output: " Q52_FMT
@ -1821,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
bbatt_delta -= 4 * rfatt_delta;
/* So do we finally need to adjust something? */
if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
b43_lo_g_ctl_mark_cur_used(dev);
if ((rfatt_delta == 0) && (bbatt_delta == 0))
return;
}
/* Calculate the new attenuation values. */
bbatt = phy->bbatt.att;
@ -1870,7 +1696,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
b43_radio_lock(dev);
b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
phy->tx_control);
b43_lo_g_ctl_mark_cur_used(dev);
b43_radio_unlock(dev);
b43_phy_unlock(dev);
break;
@ -1908,7 +1733,7 @@ static inline
f = q;
i++;
} while (delta >= 2);
entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
return 0;
}
@ -2007,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev)
else
unsupported = 1;
break;
case B43_PHYTYPE_B:
switch (phy->rev) {
case 2:
b43_phy_initb2(dev);
break;
case 4:
b43_phy_initb4(dev);
break;
case 5:
b43_phy_initb5(dev);
break;
case 6:
b43_phy_initb6(dev);
break;
default:
unsupported = 1;
}
break;
case B43_PHYTYPE_G:
b43_phy_initg(dev);
break;
@ -2043,7 +1850,7 @@ int b43_phy_init(struct b43_wldev *dev)
void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
{
struct b43_phy *phy = &dev->phy;
u32 hf;
u64 hf;
u16 tmp;
int autodiv = 0;
@ -2452,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
for (i = 0; i < 64; i++) {
tmp = b43_nrssi_hw_read(dev, i);
tmp -= val;
tmp = limit_value(tmp, -32, 31);
tmp = clamp_val(tmp, -32, 31);
b43_nrssi_hw_write(dev, i, tmp);
}
}
@ -2469,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev)
tmp = (i - delta) * phy->nrssislope;
tmp /= 0x10000;
tmp += 0x3A;
tmp = limit_value(tmp, 0, 0x3F);
tmp = clamp_val(tmp, 0, 0x3F);
phy->nrssi_lt[i] = tmp;
}
}
@ -2906,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
} else
threshold = phy->nrssi[1] - 5;
threshold = limit_value(threshold, 0, 0x3E);
threshold = clamp_val(threshold, 0, 0x3E);
b43_phy_read(dev, 0x0020); /* dummy read */
b43_phy_write(dev, 0x0020,
(((u16) threshold) << 8) | 0x001C);
@ -2957,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
else
a += 32;
a = a >> 6;
a = limit_value(a, -31, 31);
a = clamp_val(a, -31, 31);
b = b * (phy->nrssi[1] - phy->nrssi[0]);
b += (phy->nrssi[0] << 6);
@ -2966,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
else
b += 32;
b = b >> 6;
b = limit_value(b, -31, 31);
b = clamp_val(b, -31, 31);
tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
tmp_u16 |= ((u32) b & 0x0000003F);
@ -3069,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
}
radio_stacksave(0x0078);
tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
flipped = flip_4bit(tmp);
B43_WARN_ON(tmp > 15);
flipped = bitrev4(tmp);
if (flipped < 10 && flipped >= 8)
flipped = 7;
else if (flipped >= 10)
flipped -= 3;
flipped = flip_4bit(flipped);
flipped = (flipped << 1) | 0x0020;
flipped = (bitrev4(flipped) << 1) | 0x0020;
b43_radio_write16(dev, 0x0078, flipped);
b43_calc_nrssi_threshold(dev);
@ -3708,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
tmp1 >>= 9;
for (i = 0; i < 16; i++) {
radio78 = ((flip_4bit(i) << 1) | 0x20);
radio78 = (bitrev4(i) << 1) | 0x0020;
b43_radio_write16(dev, 0x78, radio78);
udelay(10);
for (j = 0; j < 16; j++) {

View File

@ -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
View 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
View 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_ */

View File

@ -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);
}
}
}

View File

@ -30,6 +30,7 @@
#include "xmit.h"
#include "phy.h"
#include "dma.h"
#include "pio.h"
/* Extract the bitrate index out of a CCK PLCP header. */
@ -184,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
const struct ieee80211_tx_info *info,
u16 cookie)
{
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data;
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
u16 fctl = le16_to_cpu(wlhdr->frame_control);
struct ieee80211_rate *fbrate;
u8 rate, rate_fb;
@ -200,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u32 mac_ctl = 0;
u16 phy_ctl = 0;
u8 extra_ft = 0;
struct ieee80211_rate *txrate;
memset(txhdr, 0, sizeof(*txhdr));
WARN_ON(!txctl->tx_rate);
rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
rate_ofdm = b43_is_ofdm_rate(rate);
fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;
rate_fb = fbrate->hw_value;
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
@ -226,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev,
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
txctl->vif,
fragment_len,
fbrate);
txhdr->dur_fb = ieee80211_generic_frame_duration(
dev->wl->hw, info->control.vif, fragment_len, fbrate);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
u8 key_idx = (u16) (txctl->key_idx);
u8 key_idx = info->control.hw_key->hw_key_idx;
struct b43_key *key;
int wlhdr_len;
size_t iv_len;
@ -252,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
}
/* Hardware appends ICV. */
plcp_fragment_len += txctl->icv_len;
plcp_fragment_len += info->control.icv_len;
key_idx = b43_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
@ -260,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t) txctl->iv_len,
iv_len = min((size_t) info->control.iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
}
@ -291,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
case 0: /* Default */
phy_ctl |= B43_TXH_PHY_ANT01AUTO;
break;
@ -315,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,
}
/* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43_TXH_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TXH_MAC_5GHZ;
if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
mac_ctl |= B43_TXH_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
(txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
(info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm;
struct b43_plcp_hdr6 *plcp;
struct ieee80211_rate *rts_cts_rate;
WARN_ON(!txctl->rts_cts_rate);
rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) {
@ -352,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
cts = (struct ieee80211_cts *)
(txhdr->new_format.rts_frame);
}
ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
txctl, cts);
info, cts);
mac_ctl |= B43_TXH_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
@ -367,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
rts = (struct ieee80211_rts *)
(txhdr->new_format.rts_frame);
}
ieee80211_rts_get(dev->wl->hw, txctl->vif,
ieee80211_rts_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
txctl, rts);
info, rts);
mac_ctl |= B43_TXH_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts);
}
@ -512,7 +514,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
u32 macstat;
u16 chanid;
u16 phytype;
u8 jssi;
int padding;
memset(&status, 0, sizeof(status));
@ -520,7 +521,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
/* Get metadata about the frame from the header. */
phystat0 = le16_to_cpu(rxhdr->phy_status0);
phystat3 = le16_to_cpu(rxhdr->phy_status3);
jssi = rxhdr->jssi;
macstat = le32_to_cpu(rxhdr->mac_status);
mactime = le16_to_cpu(rxhdr->mac_time);
chanstat = le16_to_cpu(rxhdr->channel);
@ -574,13 +574,21 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
}
}
status.ssi = b43_rssi_postprocess(dev, jssi,
(phystat0 & B43_RX_PHYST0_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE));
/* Link quality statistics */
status.noise = dev->stats.link_noise;
/* the next line looks wrong, but is what mac80211 wants */
status.signal = (jssi * 100) / B43_RX_MAX_SSI;
if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) {
// s8 rssi = max(rxhdr->power0, rxhdr->power1);
//TODO: Find out what the rssi value is (dBm or percentage?)
// and also find out what the maximum possible value is.
// Fill status.ssi and status.signal fields.
} else {
status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,
(phystat0 & B43_RX_PHYST0_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE));
status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
}
if (phystat0 & B43_RX_PHYST0_OFDM)
status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp,
phytype == B43_PHYTYPE_A);
@ -589,12 +597,16 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
/*
* If monitors are present get full 64-bit timestamp. This
* code assumes we get to process the packet within 16 bits
* of timestamp, i.e. about 65 milliseconds after the PHY
* received the first symbol.
* All frames on monitor interfaces and beacons always need a full
* 64-bit timestamp. Monitor interfaces need it for diagnostic
* purposes and beacons for IBSS merging.
* This code assumes we get to process the packet within 16 bits
* of timestamp, i.e. about 65 milliseconds after the PHY received
* the first symbol.
*/
if (dev->wl->radiotap_enabled) {
if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE))
== (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) ||
dev->wl->radiotap_enabled) {
u16 low_mactime_now;
b43_tsf_read(dev, &status.mactime);
@ -664,67 +676,54 @@ void b43_handle_txstatus(struct b43_wldev *dev,
dev->wl->ieee_stats.dot11RTSSuccessCount++;
}
b43_dma_handle_txstatus(dev, status);
if (b43_using_pio_transfers(dev))
b43_pio_handle_txstatus(dev, status);
else
b43_dma_handle_txstatus(dev, status);
}
/* Handle TX status report as received through DMA/PIO queues */
void b43_handle_hwtxstatus(struct b43_wldev *dev,
const struct b43_hwtxstatus *hw)
/* Fill out the mac80211 TXstatus report based on the b43-specific
* txstatus report data. This returns a boolean whether the frame was
* successfully transmitted. */
bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status)
{
struct b43_txstatus status;
u8 tmp;
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)
{
b43_dma_tx_suspend(dev);
if (b43_using_pio_transfers(dev))
b43_pio_tx_suspend(dev);
else
b43_dma_tx_suspend(dev);
}
/* Resume any TX operation on the device (resume the hardware queues) */
void b43_tx_resume(struct b43_wldev *dev)
{
b43_dma_tx_resume(dev);
}
#if 0
static void upload_qos_parms(struct b43_wldev *dev,
const u16 * parms, u16 offset)
{
int i;
for (i = 0; i < B43_NR_QOSPARMS; i++) {
b43_shm_write16(dev, B43_SHM_SHARED,
offset + (i * 2), parms[i]);
}
}
#endif
/* Initialize the QoS parameters */
void b43_qos_init(struct b43_wldev *dev)
{
/* FIXME: This function must probably be called from the mac80211
* config callback. */
return;
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
//FIXME kill magic
b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
/*TODO: We might need some stack support here to get the values. */
if (b43_using_pio_transfers(dev))
b43_pio_tx_resume(dev);
else
b43_dma_tx_resume(dev);
}

View File

@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, u16 cookie);
const struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */
struct b43_txstatus {
@ -207,25 +207,24 @@ enum {
B43_TXST_SUPP_ABNACK, /* Afterburner NACK */
};
/* Transmit Status as received through DMA/PIO on old chips */
struct b43_hwtxstatus {
PAD_BYTES(4);
__le16 cookie;
u8 flags;
u8 count;
PAD_BYTES(2);
__le16 seq;
u8 phy_stat;
PAD_BYTES(1);
} __attribute__ ((__packed__));
/* Receive header for v4 firmware. */
struct b43_rxhdr_fw4 {
__le16 frame_len; /* Frame length */
PAD_BYTES(2);
__le16 phy_status0; /* PHY RX Status 0 */
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
union {
/* RSSI for A/B/G-PHYs */
struct {
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
} __attribute__ ((__packed__));
/* RSSI for N-PHYs */
struct {
__s8 power0; /* PHY RX Status 1: Power 0 */
__s8 power1; /* PHY RX Status 1: Power 1 */
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
__le16 phy_status2; /* PHY RX Status 2 */
__le16 phy_status3; /* PHY RX Status 3 */
__le32 mac_status; /* MAC RX status */
@ -295,25 +294,12 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_handle_hwtxstatus(struct b43_wldev *dev,
const struct b43_hwtxstatus *hw);
bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status);
void b43_tx_suspend(struct b43_wldev *dev);
void b43_tx_resume(struct b43_wldev *dev);
#define B43_NR_QOSPARMS 22
enum {
B43_QOSPARM_TXOP = 0,
B43_QOSPARM_CWMIN,
B43_QOSPARM_CWMAX,
B43_QOSPARM_CWCUR,
B43_QOSPARM_AIFS,
B43_QOSPARM_BSLOTS,
B43_QOSPARM_REGGAP,
B43_QOSPARM_STATUS,
};
void b43_qos_init(struct b43_wldev *dev);
/* Helper functions for converting the key-table index from "firmware-format"
* to "raw-format" and back. The firmware API changed for this at some revision.