Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
9bff9dbd00
|
@ -260,6 +260,9 @@ config ACPI_ASUS
|
|||
config ACPI_TOSHIBA
|
||||
tristate "Toshiba Laptop Extras"
|
||||
depends on X86
|
||||
select INPUT_POLLDEV
|
||||
select NET
|
||||
select RFKILL
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver adds support for access to certain system settings
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
*
|
||||
* Copyright (C) 2002-2004 John Belmonte
|
||||
* Copyright (C) 2008 Philip Langdale
|
||||
*
|
||||
* 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
|
||||
|
@ -33,7 +34,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define TOSHIBA_ACPI_VERSION "0.18"
|
||||
#define TOSHIBA_ACPI_VERSION "0.19"
|
||||
#define PROC_INTERFACE_VERSION 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -42,6 +43,9 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -90,6 +94,7 @@ MODULE_LICENSE("GPL");
|
|||
#define HCI_VIDEO_OUT 0x001c
|
||||
#define HCI_HOTKEY_EVENT 0x001e
|
||||
#define HCI_LCD_BRIGHTNESS 0x002a
|
||||
#define HCI_WIRELESS 0x0056
|
||||
|
||||
/* field definitions */
|
||||
#define HCI_LCD_BRIGHTNESS_BITS 3
|
||||
|
@ -98,9 +103,14 @@ MODULE_LICENSE("GPL");
|
|||
#define HCI_VIDEO_OUT_LCD 0x1
|
||||
#define HCI_VIDEO_OUT_CRT 0x2
|
||||
#define HCI_VIDEO_OUT_TV 0x4
|
||||
#define HCI_WIRELESS_KILL_SWITCH 0x01
|
||||
#define HCI_WIRELESS_BT_PRESENT 0x0f
|
||||
#define HCI_WIRELESS_BT_ATTACH 0x40
|
||||
#define HCI_WIRELESS_BT_POWER 0x80
|
||||
|
||||
static const struct acpi_device_id toshiba_device_ids[] = {
|
||||
{"TOS6200", 0},
|
||||
{"TOS6208", 0},
|
||||
{"TOS1900", 0},
|
||||
{"", 0},
|
||||
};
|
||||
|
@ -193,7 +203,7 @@ static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
|
|||
return status;
|
||||
}
|
||||
|
||||
/* common hci tasks (get or set one value)
|
||||
/* common hci tasks (get or set one or two value)
|
||||
*
|
||||
* In addition to the ACPI status, the HCI system returns a result which
|
||||
* may be useful (such as "not supported").
|
||||
|
@ -218,6 +228,152 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
|
|||
return status;
|
||||
}
|
||||
|
||||
static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
|
||||
{
|
||||
u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
|
||||
u32 out[HCI_WORDS];
|
||||
acpi_status status = hci_raw(in, out);
|
||||
*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
|
||||
{
|
||||
u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
|
||||
u32 out[HCI_WORDS];
|
||||
acpi_status status = hci_raw(in, out);
|
||||
*out1 = out[2];
|
||||
*out2 = out[3];
|
||||
*result = (status == AE_OK) ? out[0] : HCI_FAILURE;
|
||||
return status;
|
||||
}
|
||||
|
||||
struct toshiba_acpi_dev {
|
||||
struct platform_device *p_dev;
|
||||
struct rfkill *rfk_dev;
|
||||
struct input_polled_dev *poll_dev;
|
||||
|
||||
const char *bt_name;
|
||||
const char *rfk_name;
|
||||
|
||||
bool last_rfk_state;
|
||||
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static struct toshiba_acpi_dev toshiba_acpi = {
|
||||
.bt_name = "Toshiba Bluetooth",
|
||||
.rfk_name = "Toshiba RFKill Switch",
|
||||
.last_rfk_state = false,
|
||||
};
|
||||
|
||||
/* Bluetooth rfkill handlers */
|
||||
|
||||
static u32 hci_get_bt_present(bool *present)
|
||||
{
|
||||
u32 hci_result;
|
||||
u32 value, value2;
|
||||
|
||||
value = 0;
|
||||
value2 = 0;
|
||||
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS)
|
||||
*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
|
||||
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static u32 hci_get_bt_on(bool *on)
|
||||
{
|
||||
u32 hci_result;
|
||||
u32 value, value2;
|
||||
|
||||
value = 0;
|
||||
value2 = 0x0001;
|
||||
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS)
|
||||
*on = (value & HCI_WIRELESS_BT_POWER) &&
|
||||
(value & HCI_WIRELESS_BT_ATTACH);
|
||||
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static u32 hci_get_radio_state(bool *radio_state)
|
||||
{
|
||||
u32 hci_result;
|
||||
u32 value, value2;
|
||||
|
||||
value = 0;
|
||||
value2 = 0x0001;
|
||||
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
|
||||
|
||||
*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
|
||||
return hci_result;
|
||||
}
|
||||
|
||||
static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
|
||||
{
|
||||
u32 result1, result2;
|
||||
u32 value;
|
||||
bool radio_state;
|
||||
struct toshiba_acpi_dev *dev = data;
|
||||
|
||||
value = (state == RFKILL_STATE_UNBLOCKED);
|
||||
|
||||
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
|
||||
return -EFAULT;
|
||||
|
||||
switch (state) {
|
||||
case RFKILL_STATE_UNBLOCKED:
|
||||
if (!radio_state)
|
||||
return -EPERM;
|
||||
break;
|
||||
case RFKILL_STATE_SOFT_BLOCKED:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
|
||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
|
||||
{
|
||||
bool state_changed;
|
||||
bool new_rfk_state;
|
||||
bool value;
|
||||
u32 hci_result;
|
||||
struct toshiba_acpi_dev *dev = poll_dev->private;
|
||||
|
||||
hci_result = hci_get_radio_state(&value);
|
||||
if (hci_result != HCI_SUCCESS)
|
||||
return; /* Can't do anything useful */
|
||||
|
||||
new_rfk_state = value;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
state_changed = new_rfk_state != dev->last_rfk_state;
|
||||
dev->last_rfk_state = new_rfk_state;
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
if (unlikely(state_changed)) {
|
||||
rfkill_force_state(dev->rfk_dev,
|
||||
new_rfk_state ?
|
||||
RFKILL_STATE_SOFT_BLOCKED :
|
||||
RFKILL_STATE_HARD_BLOCKED);
|
||||
input_report_switch(poll_dev->input, SW_RFKILL_ALL,
|
||||
new_rfk_state);
|
||||
}
|
||||
}
|
||||
|
||||
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
|
||||
static struct backlight_device *toshiba_backlight_device;
|
||||
static int force_fan;
|
||||
|
@ -547,6 +703,14 @@ static struct backlight_ops toshiba_backlight_data = {
|
|||
|
||||
static void toshiba_acpi_exit(void)
|
||||
{
|
||||
if (toshiba_acpi.poll_dev) {
|
||||
input_unregister_polled_device(toshiba_acpi.poll_dev);
|
||||
input_free_polled_device(toshiba_acpi.poll_dev);
|
||||
}
|
||||
|
||||
if (toshiba_acpi.rfk_dev)
|
||||
rfkill_unregister(toshiba_acpi.rfk_dev);
|
||||
|
||||
if (toshiba_backlight_device)
|
||||
backlight_device_unregister(toshiba_backlight_device);
|
||||
|
||||
|
@ -555,6 +719,8 @@ static void toshiba_acpi_exit(void)
|
|||
if (toshiba_proc_dir)
|
||||
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
||||
|
||||
platform_device_unregister(toshiba_acpi.p_dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -562,6 +728,10 @@ static int __init toshiba_acpi_init(void)
|
|||
{
|
||||
acpi_status status = AE_OK;
|
||||
u32 hci_result;
|
||||
bool bt_present;
|
||||
bool bt_on;
|
||||
bool radio_on;
|
||||
int ret = 0;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
@ -578,6 +748,18 @@ static int __init toshiba_acpi_init(void)
|
|||
TOSHIBA_ACPI_VERSION);
|
||||
printk(MY_INFO " HCI method: %s\n", method_hci);
|
||||
|
||||
mutex_init(&toshiba_acpi.mutex);
|
||||
|
||||
toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(toshiba_acpi.p_dev)) {
|
||||
ret = PTR_ERR(toshiba_acpi.p_dev);
|
||||
printk(MY_ERR "unable to register platform device\n");
|
||||
toshiba_acpi.p_dev = NULL;
|
||||
toshiba_acpi_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
force_fan = 0;
|
||||
key_event_valid = 0;
|
||||
|
||||
|
@ -586,19 +768,23 @@ static int __init toshiba_acpi_init(void)
|
|||
|
||||
toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
|
||||
if (!toshiba_proc_dir) {
|
||||
status = AE_ERROR;
|
||||
toshiba_acpi_exit();
|
||||
return -ENODEV;
|
||||
} else {
|
||||
toshiba_proc_dir->owner = THIS_MODULE;
|
||||
status = add_device();
|
||||
if (ACPI_FAILURE(status))
|
||||
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
toshiba_acpi_exit();
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
toshiba_backlight_device = backlight_device_register("toshiba",NULL,
|
||||
toshiba_backlight_device = backlight_device_register("toshiba",
|
||||
&toshiba_acpi.p_dev->dev,
|
||||
NULL,
|
||||
&toshiba_backlight_data);
|
||||
if (IS_ERR(toshiba_backlight_device)) {
|
||||
int ret = PTR_ERR(toshiba_backlight_device);
|
||||
ret = PTR_ERR(toshiba_backlight_device);
|
||||
|
||||
printk(KERN_ERR "Could not register toshiba backlight device\n");
|
||||
toshiba_backlight_device = NULL;
|
||||
|
@ -607,7 +793,66 @@ static int __init toshiba_acpi_init(void)
|
|||
}
|
||||
toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
|
||||
|
||||
return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
|
||||
/* Register rfkill switch for Bluetooth */
|
||||
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
|
||||
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH);
|
||||
if (!toshiba_acpi.rfk_dev) {
|
||||
printk(MY_ERR "unable to allocate rfkill device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
|
||||
toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
|
||||
toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
|
||||
toshiba_acpi.rfk_dev->data = &toshiba_acpi;
|
||||
|
||||
if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
|
||||
} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
|
||||
radio_on) {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
|
||||
} else {
|
||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
|
||||
}
|
||||
|
||||
ret = rfkill_register(toshiba_acpi.rfk_dev);
|
||||
if (ret) {
|
||||
printk(MY_ERR "unable to register rfkill device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register input device for kill switch */
|
||||
toshiba_acpi.poll_dev = input_allocate_polled_device();
|
||||
if (!toshiba_acpi.poll_dev) {
|
||||
printk(MY_ERR "unable to allocate kill-switch input device\n");
|
||||
toshiba_acpi_exit();
|
||||
return -ENOMEM;
|
||||
}
|
||||
toshiba_acpi.poll_dev->private = &toshiba_acpi;
|
||||
toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
|
||||
toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
|
||||
|
||||
toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
|
||||
toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
|
||||
toshiba_acpi.poll_dev->input->id.vendor = 0x0930; /* Toshiba USB ID */
|
||||
set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
|
||||
set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
|
||||
input_report_switch(toshiba_acpi.poll_dev->input, SW_RFKILL_ALL, TRUE);
|
||||
|
||||
ret = input_register_polled_device(toshiba_acpi.poll_dev);
|
||||
if (ret) {
|
||||
printk(MY_ERR "unable to register kill-switch input device\n");
|
||||
rfkill_free(toshiba_acpi.rfk_dev);
|
||||
toshiba_acpi.rfk_dev = NULL;
|
||||
toshiba_acpi_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(toshiba_acpi_init);
|
||||
|
|
|
@ -1884,6 +1884,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
|
|||
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
|
||||
/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
|
||||
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
dev->channel_change_time = 1000;
|
||||
dev->max_signal = 100; /* FIXME: find better value */
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
ath5k-y += base.o
|
||||
ath5k-y += hw.o
|
||||
ath5k-y += caps.o
|
||||
ath5k-y += initvals.o
|
||||
ath5k-y += eeprom.o
|
||||
ath5k-y += gpio.o
|
||||
ath5k-y += desc.o
|
||||
ath5k-y += dma.o
|
||||
ath5k-y += qcu.o
|
||||
ath5k-y += pcu.o
|
||||
ath5k-y += phy.o
|
||||
ath5k-y += reset.o
|
||||
ath5k-y += attach.o
|
||||
ath5k-y += base.o
|
||||
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ATH5K) += ath5k.o
|
||||
|
|
|
@ -18,18 +18,23 @@
|
|||
#ifndef _ATH5K_H
|
||||
#define _ATH5K_H
|
||||
|
||||
/* Set this to 1 to disable regulatory domain restrictions for channel tests.
|
||||
* WARNING: This is for debuging only and has side effects (eg. scan takes too
|
||||
* long and results timeouts). It's also illegal to tune to some of the
|
||||
* supported frequencies in some countries, so use this at your own risk,
|
||||
* you've been warned. */
|
||||
/* TODO: Clean up channel debuging -doesn't work anyway- and start
|
||||
* working on reg. control code using all available eeprom information
|
||||
* -rev. engineering needed- */
|
||||
#define CHAN_DEBUG 0
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "hw.h"
|
||||
/* RX/TX descriptor hw structs
|
||||
* TODO: Driver part should only see sw structs */
|
||||
#include "desc.h"
|
||||
|
||||
/* EEPROM structs/offsets
|
||||
* TODO: Make a more generic struct (eg. add more stuff to ath5k_capabilities)
|
||||
* and clean up common bits, then introduce set/get functions in eeprom.c */
|
||||
#include "eeprom.h"
|
||||
|
||||
/* PCI IDs */
|
||||
#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */
|
||||
|
@ -86,8 +91,93 @@
|
|||
#define ATH5K_ERR(_sc, _fmt, ...) \
|
||||
ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* AR5K REGISTER ACCESS
|
||||
*/
|
||||
|
||||
/* Some macros to read/write fields */
|
||||
|
||||
/* First shift, then mask */
|
||||
#define AR5K_REG_SM(_val, _flags) \
|
||||
(((_val) << _flags##_S) & (_flags))
|
||||
|
||||
/* First mask, then shift */
|
||||
#define AR5K_REG_MS(_val, _flags) \
|
||||
(((_val) & (_flags)) >> _flags##_S)
|
||||
|
||||
/* Some registers can hold multiple values of interest. For this
|
||||
* reason when we want to write to these registers we must first
|
||||
* retrieve the values which we do not want to clear (lets call this
|
||||
* old_data) and then set the register with this and our new_value:
|
||||
* ( old_data | new_value) */
|
||||
#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \
|
||||
ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
|
||||
(((_val) << _flags##_S) & (_flags)), _reg)
|
||||
|
||||
#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \
|
||||
ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \
|
||||
(_mask)) | (_flags), _reg)
|
||||
|
||||
#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
|
||||
|
||||
#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
|
||||
|
||||
/* Access to PHY registers */
|
||||
#define AR5K_PHY_READ(ah, _reg) \
|
||||
ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
#define AR5K_PHY_WRITE(ah, _reg, _val) \
|
||||
ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
/* Access QCU registers per queue */
|
||||
#define AR5K_REG_READ_Q(ah, _reg, _queue) \
|
||||
(ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \
|
||||
|
||||
#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \
|
||||
ath5k_hw_reg_write(ah, (1 << _queue), _reg)
|
||||
|
||||
#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \
|
||||
_reg |= 1 << _queue; \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \
|
||||
_reg &= ~(1 << _queue); \
|
||||
} while (0)
|
||||
|
||||
/* Used while writing initvals */
|
||||
#define AR5K_REG_WAIT(_i) do { \
|
||||
if (_i % 64) \
|
||||
udelay(1); \
|
||||
} while (0)
|
||||
|
||||
/* Register dumps are done per operation mode */
|
||||
#define AR5K_INI_RFGAIN_5GHZ 0
|
||||
#define AR5K_INI_RFGAIN_2GHZ 1
|
||||
|
||||
/* TODO: Clean this up */
|
||||
#define AR5K_INI_VAL_11A 0
|
||||
#define AR5K_INI_VAL_11A_TURBO 1
|
||||
#define AR5K_INI_VAL_11B 2
|
||||
#define AR5K_INI_VAL_11G 3
|
||||
#define AR5K_INI_VAL_11G_TURBO 4
|
||||
#define AR5K_INI_VAL_XR 0
|
||||
#define AR5K_INI_VAL_MAX 5
|
||||
|
||||
#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
|
||||
/* Used for BSSID etc manipulation */
|
||||
#define AR5K_LOW_ID(_a)( \
|
||||
(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
|
||||
)
|
||||
|
||||
#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8)
|
||||
|
||||
/*
|
||||
* Some tuneable values (these should be changeable by the user)
|
||||
* TODO: Make use of them and add more options OR use debug/configfs
|
||||
*/
|
||||
#define AR5K_TUNE_DMA_BEACON_RESP 2
|
||||
#define AR5K_TUNE_SW_BEACON_RESP 10
|
||||
|
@ -98,13 +188,13 @@
|
|||
#define AR5K_TUNE_REGISTER_TIMEOUT 20000
|
||||
/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
|
||||
* be the max value. */
|
||||
#define AR5K_TUNE_RSSI_THRES 129
|
||||
#define AR5K_TUNE_RSSI_THRES 129
|
||||
/* This must be set when setting the RSSI threshold otherwise it can
|
||||
* prevent a reset. If AR5K_RSSI_THR is read after writing to it
|
||||
* the BMISS_THRES will be seen as 0, seems harware doesn't keep
|
||||
* track of it. Max value depends on harware. For AR5210 this is just 7.
|
||||
* For AR5211+ this seems to be up to 255. */
|
||||
#define AR5K_TUNE_BMISS_THRES 7
|
||||
#define AR5K_TUNE_BMISS_THRES 7
|
||||
#define AR5K_TUNE_REGISTER_DWELL_TIME 20000
|
||||
#define AR5K_TUNE_BEACON_INTERVAL 100
|
||||
#define AR5K_TUNE_AIFS 2
|
||||
|
@ -123,6 +213,55 @@
|
|||
#define AR5K_TUNE_ANT_DIVERSITY true
|
||||
#define AR5K_TUNE_HWTXTRIES 4
|
||||
|
||||
#define AR5K_INIT_CARR_SENSE_EN 1
|
||||
|
||||
/*Swap RX/TX Descriptor for big endian archs*/
|
||||
#if defined(__BIG_ENDIAN)
|
||||
#define AR5K_INIT_CFG ( \
|
||||
AR5K_CFG_SWTD | AR5K_CFG_SWRD \
|
||||
)
|
||||
#else
|
||||
#define AR5K_INIT_CFG 0x00000000
|
||||
#endif
|
||||
|
||||
/* Initial values */
|
||||
#define AR5K_INIT_TX_LATENCY 502
|
||||
#define AR5K_INIT_USEC 39
|
||||
#define AR5K_INIT_USEC_TURBO 79
|
||||
#define AR5K_INIT_USEC_32 31
|
||||
#define AR5K_INIT_SLOT_TIME 396
|
||||
#define AR5K_INIT_SLOT_TIME_TURBO 480
|
||||
#define AR5K_INIT_ACK_CTS_TIMEOUT 1024
|
||||
#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800
|
||||
#define AR5K_INIT_PROG_IFS 920
|
||||
#define AR5K_INIT_PROG_IFS_TURBO 960
|
||||
#define AR5K_INIT_EIFS 3440
|
||||
#define AR5K_INIT_EIFS_TURBO 6880
|
||||
#define AR5K_INIT_SIFS 560
|
||||
#define AR5K_INIT_SIFS_TURBO 480
|
||||
#define AR5K_INIT_SH_RETRY 10
|
||||
#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY
|
||||
#define AR5K_INIT_SSH_RETRY 32
|
||||
#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY
|
||||
#define AR5K_INIT_TX_RETRY 10
|
||||
|
||||
#define AR5K_INIT_TRANSMIT_LATENCY ( \
|
||||
(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
|
||||
(AR5K_INIT_USEC) \
|
||||
)
|
||||
#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \
|
||||
(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
|
||||
(AR5K_INIT_USEC_TURBO) \
|
||||
)
|
||||
#define AR5K_INIT_PROTO_TIME_CNTRL ( \
|
||||
(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \
|
||||
(AR5K_INIT_PROG_IFS) \
|
||||
)
|
||||
#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \
|
||||
(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
|
||||
(AR5K_INIT_PROG_IFS_TURBO) \
|
||||
)
|
||||
|
||||
/* token to use for aifs, cwmin, cwmax in MadWiFi */
|
||||
#define AR5K_TXQ_USEDEFAULT ((u32) -1)
|
||||
|
||||
|
@ -196,7 +335,6 @@ struct ath5k_srev_name {
|
|||
#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */
|
||||
|
||||
/* IEEE defs */
|
||||
|
||||
#define IEEE80211_MAX_LEN 2500
|
||||
|
||||
/* TODO add support to mac80211 for vendor-specific rates and modes */
|
||||
|
@ -268,16 +406,13 @@ enum ath5k_driver_mode {
|
|||
AR5K_MODE_MAX = 5
|
||||
};
|
||||
|
||||
/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
|
||||
#define AR5K_SET_SHORT_PREAMBLE 0x04
|
||||
|
||||
|
||||
/****************\
|
||||
TX DEFINITIONS
|
||||
\****************/
|
||||
|
||||
/*
|
||||
* TX Status
|
||||
* TX Status descriptor
|
||||
*/
|
||||
struct ath5k_tx_status {
|
||||
u16 ts_seqnum;
|
||||
|
@ -349,7 +484,6 @@ enum ath5k_tx_queue_id {
|
|||
AR5K_TX_QUEUE_ID_XR_DATA = 9,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Flags to set hw queue's parameters...
|
||||
*/
|
||||
|
@ -382,7 +516,8 @@ struct ath5k_txq_info {
|
|||
|
||||
/*
|
||||
* Transmit packet types.
|
||||
* These are not fully used inside OpenHAL yet
|
||||
* used on tx control descriptor
|
||||
* TODO: Use them inside base.c corectly
|
||||
*/
|
||||
enum ath5k_pkt_type {
|
||||
AR5K_PKT_TYPE_NORMAL = 0,
|
||||
|
@ -425,7 +560,7 @@ enum ath5k_dmasize {
|
|||
\****************/
|
||||
|
||||
/*
|
||||
* RX Status
|
||||
* RX Status descriptor
|
||||
*/
|
||||
struct ath5k_rx_status {
|
||||
u16 rs_datalen;
|
||||
|
@ -489,34 +624,59 @@ struct ath5k_beacon_state {
|
|||
#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
|
||||
|
||||
|
||||
/*******************************\
|
||||
GAIN OPTIMIZATION DEFINITIONS
|
||||
\*******************************/
|
||||
|
||||
enum ath5k_rfgain {
|
||||
AR5K_RFGAIN_INACTIVE = 0,
|
||||
AR5K_RFGAIN_READ_REQUESTED,
|
||||
AR5K_RFGAIN_NEED_CHANGE,
|
||||
};
|
||||
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
|
||||
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
|
||||
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
|
||||
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
|
||||
#define AR5K_GAIN_CCK_PROBE_CORR 5
|
||||
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
|
||||
#define AR5K_GAIN_STEP_COUNT 10
|
||||
#define AR5K_GAIN_PARAM_TX_CLIP 0
|
||||
#define AR5K_GAIN_PARAM_PD_90 1
|
||||
#define AR5K_GAIN_PARAM_PD_84 2
|
||||
#define AR5K_GAIN_PARAM_GAIN_SEL 3
|
||||
#define AR5K_GAIN_PARAM_MIX_ORN 0
|
||||
#define AR5K_GAIN_PARAM_PD_138 1
|
||||
#define AR5K_GAIN_PARAM_PD_137 2
|
||||
#define AR5K_GAIN_PARAM_PD_136 3
|
||||
#define AR5K_GAIN_PARAM_PD_132 4
|
||||
#define AR5K_GAIN_PARAM_PD_131 5
|
||||
#define AR5K_GAIN_PARAM_PD_130 6
|
||||
#define AR5K_GAIN_CHECK_ADJUST(_g) \
|
||||
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
|
||||
|
||||
struct ath5k_gain_opt_step {
|
||||
s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
|
||||
s32 gos_gain;
|
||||
};
|
||||
|
||||
struct ath5k_gain {
|
||||
u32 g_step_idx;
|
||||
u32 g_current;
|
||||
u32 g_target;
|
||||
u32 g_low;
|
||||
u32 g_high;
|
||||
u32 g_f_corr;
|
||||
u32 g_active;
|
||||
const struct ath5k_gain_opt_step *g_step;
|
||||
};
|
||||
|
||||
|
||||
/********************\
|
||||
COMMON DEFINITIONS
|
||||
\********************/
|
||||
|
||||
/*
|
||||
* Atheros hardware descriptor
|
||||
* This is read and written to by the hardware
|
||||
*/
|
||||
struct ath5k_desc {
|
||||
u32 ds_link; /* physical address of the next descriptor */
|
||||
u32 ds_data; /* physical address of data buffer (skb) */
|
||||
|
||||
union {
|
||||
struct ath5k_hw_5210_tx_desc ds_tx5210;
|
||||
struct ath5k_hw_5212_tx_desc ds_tx5212;
|
||||
struct ath5k_hw_all_rx_desc ds_rx;
|
||||
} ud;
|
||||
} __packed;
|
||||
|
||||
#define AR5K_RXDESC_INTREQ 0x0020
|
||||
|
||||
#define AR5K_TXDESC_CLRDMASK 0x0001
|
||||
#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/
|
||||
#define AR5K_TXDESC_RTSENA 0x0004
|
||||
#define AR5K_TXDESC_CTSENA 0x0008
|
||||
#define AR5K_TXDESC_INTREQ 0x0010
|
||||
#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/
|
||||
|
||||
#define AR5K_SLOT_TIME_9 396
|
||||
#define AR5K_SLOT_TIME_20 880
|
||||
#define AR5K_SLOT_TIME_MAX 0xffff
|
||||
|
@ -548,15 +708,16 @@ struct ath5k_desc {
|
|||
#define CHANNEL_MODES CHANNEL_ALL
|
||||
|
||||
/*
|
||||
* Used internaly in OpenHAL (ar5211.c/ar5212.c
|
||||
* for reset_tx_queue). Also see struct struct ieee80211_channel.
|
||||
* Used internaly for reset_tx_queue).
|
||||
* Also see struct struct ieee80211_channel.
|
||||
*/
|
||||
#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
|
||||
#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
|
||||
|
||||
/*
|
||||
* The following structure will be used to map 2GHz channels to
|
||||
* The following structure is used to map 2GHz channels to
|
||||
* 5GHz Atheros channels.
|
||||
* TODO: Clean up
|
||||
*/
|
||||
struct ath5k_athchan_2ghz {
|
||||
u32 a2_flags;
|
||||
|
@ -564,9 +725,9 @@ struct ath5k_athchan_2ghz {
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
* Rate definitions
|
||||
*/
|
||||
/******************\
|
||||
RATE DEFINITIONS
|
||||
\******************/
|
||||
|
||||
/**
|
||||
* Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
|
||||
|
@ -618,6 +779,8 @@ struct ath5k_athchan_2ghz {
|
|||
#define ATH5K_RATE_CODE_XR_2M 0x06
|
||||
#define ATH5K_RATE_CODE_XR_3M 0x01
|
||||
|
||||
/* adding this flag to rate_code enables short preamble */
|
||||
#define AR5K_SET_SHORT_PREAMBLE 0x04
|
||||
|
||||
/*
|
||||
* Crypto definitions
|
||||
|
@ -639,7 +802,6 @@ struct ath5k_athchan_2ghz {
|
|||
return (false); \
|
||||
} while (0)
|
||||
|
||||
|
||||
enum ath5k_ant_setting {
|
||||
AR5K_ANT_VARIABLE = 0, /* variable by programming */
|
||||
AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */
|
||||
|
@ -750,7 +912,8 @@ enum ath5k_power_mode {
|
|||
|
||||
/*
|
||||
* These match net80211 definitions (not used in
|
||||
* d80211).
|
||||
* mac80211).
|
||||
* TODO: Clean this up
|
||||
*/
|
||||
#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/
|
||||
#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/
|
||||
|
@ -766,7 +929,8 @@ enum ath5k_power_mode {
|
|||
/*
|
||||
* Chipset capabilities -see ath5k_hw_get_capability-
|
||||
* get_capability function is not yet fully implemented
|
||||
* in OpenHAL so most of these don't work yet...
|
||||
* in ath5k so most of these don't work yet...
|
||||
* TODO: Implement these & merge with _TUNE_ stuff above
|
||||
*/
|
||||
enum ath5k_capability_type {
|
||||
AR5K_CAP_REG_DMN = 0, /* Used to get current reg. domain id */
|
||||
|
@ -835,6 +999,7 @@ struct ath5k_capabilities {
|
|||
#define AR5K_MAX_GPIO 10
|
||||
#define AR5K_MAX_RF_BANKS 8
|
||||
|
||||
/* TODO: Clean up and merge with ath5k_softc */
|
||||
struct ath5k_hw {
|
||||
u32 ah_magic;
|
||||
|
||||
|
@ -927,11 +1092,13 @@ struct ath5k_hw {
|
|||
/*
|
||||
* Function pointers
|
||||
*/
|
||||
int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||
u32 size, unsigned int flags);
|
||||
int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
|
||||
unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int);
|
||||
int (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
|
||||
int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int,
|
||||
unsigned int, unsigned int);
|
||||
int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
|
||||
|
@ -944,33 +1111,38 @@ struct ath5k_hw {
|
|||
* Prototypes
|
||||
*/
|
||||
|
||||
/* General Functions */
|
||||
extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set);
|
||||
/* Attach/Detach Functions */
|
||||
extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
|
||||
extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode);
|
||||
extern void ath5k_hw_detach(struct ath5k_hw *ah);
|
||||
|
||||
/* Reset Functions */
|
||||
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
|
||||
extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
|
||||
/* Power management functions */
|
||||
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
|
||||
|
||||
/* DMA Related Functions */
|
||||
extern void ath5k_hw_start_rx(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
|
||||
extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr);
|
||||
extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
|
||||
extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr);
|
||||
extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
|
||||
u32 phys_addr);
|
||||
extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
|
||||
/* Interrupt handling */
|
||||
extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
|
||||
extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
|
||||
extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum
|
||||
ath5k_int new_mask);
|
||||
extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
|
||||
|
||||
/* EEPROM access functions */
|
||||
extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
|
||||
extern int ath5k_eeprom_init(struct ath5k_hw *ah);
|
||||
extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
|
||||
|
||||
/* Protocol Control Unit Functions */
|
||||
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
|
||||
/* BSSID Functions */
|
||||
|
@ -980,14 +1152,14 @@ extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc
|
|||
extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
|
||||
/* Receive start/stop functions */
|
||||
extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
|
||||
/* RX Filter functions */
|
||||
extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
|
||||
extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index);
|
||||
extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
|
||||
extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
|
||||
extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
|
||||
/* Beacon related functions */
|
||||
/* Beacon control functions */
|
||||
extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
|
||||
extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
|
||||
extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
|
||||
|
@ -1009,61 +1181,129 @@ extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
|
|||
extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
|
||||
extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
|
||||
extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
|
||||
|
||||
/* Queue Control Unit, DFS Control Unit Functions */
|
||||
extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info);
|
||||
extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info);
|
||||
extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
|
||||
extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
const struct ath5k_txq_info *queue_info);
|
||||
extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
|
||||
enum ath5k_tx_queue queue_type,
|
||||
struct ath5k_txq_info *queue_info);
|
||||
extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
|
||||
extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
|
||||
extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
|
||||
|
||||
/* Hardware Descriptor Functions */
|
||||
extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags);
|
||||
extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
|
||||
|
||||
/* GPIO Functions */
|
||||
extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
|
||||
extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
|
||||
extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
|
||||
extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
|
||||
extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
|
||||
extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
|
||||
extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
|
||||
/* Misc functions */
|
||||
extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
|
||||
|
||||
/* Misc functions */
|
||||
int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
|
||||
extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
|
||||
extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
|
||||
|
||||
/* Initial register settings functions */
|
||||
extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
|
||||
|
||||
/* Initialize RF */
|
||||
extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
|
||||
extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
|
||||
extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
|
||||
|
||||
|
||||
/* PHY/RF channel functions */
|
||||
extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
|
||||
extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
/* PHY calibration */
|
||||
extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
|
||||
extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
|
||||
/* Misc PHY functions */
|
||||
extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
|
||||
extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
|
||||
extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
|
||||
extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
|
||||
extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
|
||||
/* TX power setup */
|
||||
extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower);
|
||||
extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
|
||||
|
||||
/*
|
||||
* Functions used internaly
|
||||
*/
|
||||
|
||||
/*
|
||||
* Translate usec to hw clock units
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
|
||||
{
|
||||
return turbo ? (usec * 80) : (usec * 40);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate hw clock units to usec
|
||||
*/
|
||||
static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
|
||||
{
|
||||
return turbo ? (clock / 80) : (clock / 40);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from a register
|
||||
*/
|
||||
static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
|
||||
{
|
||||
return ioread32(ah->ah_iobase + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to a register
|
||||
*/
|
||||
static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
|
||||
{
|
||||
iowrite32(val, ah->ah_iobase + reg);
|
||||
}
|
||||
|
||||
#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
|
||||
/*
|
||||
* Check if a register write has been completed
|
||||
*/
|
||||
static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
|
||||
u32 val, bool is_set)
|
||||
{
|
||||
int i;
|
||||
u32 data;
|
||||
|
||||
for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
|
||||
data = ath5k_hw_reg_read(ah, reg);
|
||||
if (is_set && (data & flag))
|
||||
break;
|
||||
else if ((data & flag) == val)
|
||||
break;
|
||||
udelay(15);
|
||||
}
|
||||
|
||||
return (i <= 0) ? -EAGAIN : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
|
||||
{
|
||||
u32 retval = 0, bit, i;
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
bit = (val >> i) & 1;
|
||||
retval = (retval << 1) | bit;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************\
|
||||
* Attach/Detach Functions and helpers *
|
||||
\*************************************/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/**
|
||||
* ath5k_hw_post - Power On Self Test helper function
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
static int ath5k_hw_post(struct ath5k_hw *ah)
|
||||
{
|
||||
|
||||
int i, c;
|
||||
u16 cur_reg;
|
||||
u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
|
||||
u32 var_pattern;
|
||||
u32 static_pattern[4] = {
|
||||
0x55555555, 0xaaaaaaaa,
|
||||
0x66666666, 0x99999999
|
||||
};
|
||||
u32 init_val;
|
||||
u32 cur_val;
|
||||
|
||||
for (c = 0; c < 2; c++) {
|
||||
|
||||
cur_reg = regs[c];
|
||||
|
||||
/* Save previous value */
|
||||
init_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
var_pattern = i << 16 | i;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
cur_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
if (cur_val != var_pattern) {
|
||||
ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Found on ndiswrapper dumps */
|
||||
var_pattern = 0x0039080f;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
var_pattern = static_pattern[i];
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
cur_val = ath5k_hw_reg_read(ah, cur_reg);
|
||||
|
||||
if (cur_val != var_pattern) {
|
||||
ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Found on ndiswrapper dumps */
|
||||
var_pattern = 0x003b080f;
|
||||
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
|
||||
}
|
||||
|
||||
/* Restore previous value */
|
||||
ath5k_hw_reg_write(ah, init_val, cur_reg);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_attach - Check if hw is supported and init the needed structs
|
||||
*
|
||||
* @sc: The &struct ath5k_softc we got from the driver's attach function
|
||||
* @mac_version: The mac version id (check out ath5k.h) based on pci id
|
||||
*
|
||||
* Check if the device is supported, perform a POST and initialize the needed
|
||||
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
|
||||
* -ENODEV if the device is not supported or prints an error msg if something
|
||||
* else went wrong.
|
||||
*/
|
||||
struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
||||
{
|
||||
struct ath5k_hw *ah;
|
||||
struct pci_dev *pdev = sc->pdev;
|
||||
u8 mac[ETH_ALEN];
|
||||
int ret;
|
||||
u32 srev;
|
||||
|
||||
/*If we passed the test malloc a ath5k_hw struct*/
|
||||
ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
|
||||
if (ah == NULL) {
|
||||
ret = -ENOMEM;
|
||||
ATH5K_ERR(sc, "out of memory\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ah->ah_sc = sc;
|
||||
ah->ah_iobase = sc->iobase;
|
||||
|
||||
/*
|
||||
* HW information
|
||||
*/
|
||||
ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
|
||||
ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
|
||||
ah->ah_turbo = false;
|
||||
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
|
||||
ah->ah_imr = 0;
|
||||
ah->ah_atim_window = 0;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS;
|
||||
ah->ah_cw_min = AR5K_TUNE_CWMIN;
|
||||
ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
|
||||
ah->ah_software_retry = false;
|
||||
ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
|
||||
|
||||
/*
|
||||
* Set the mac revision based on the pci id
|
||||
*/
|
||||
ah->ah_version = mac_version;
|
||||
|
||||
/*Fill the ath5k_hw struct with the needed functions*/
|
||||
ret = ath5k_hw_init_desc_functions(ah);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
/* Bring device out of sleep and reset it's units */
|
||||
ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
/* Get MAC, PHY and RADIO revisions */
|
||||
srev = ath5k_hw_reg_read(ah, AR5K_SREV);
|
||||
ah->ah_mac_srev = srev;
|
||||
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
|
||||
ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
|
||||
ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
|
||||
0xffffffff;
|
||||
ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_5GHZ);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ah->ah_radio_2ghz_revision = 0;
|
||||
else
|
||||
ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
|
||||
CHANNEL_2GHZ);
|
||||
|
||||
/* Return on unsuported chips (unsupported eeprom etc) */
|
||||
if ((srev >= AR5K_SREV_VER_AR5416) &&
|
||||
(srev < AR5K_SREV_VER_AR2425)) {
|
||||
ATH5K_ERR(sc, "Device not yet supported.\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free;
|
||||
} else if (srev == AR5K_SREV_VER_AR2425) {
|
||||
ATH5K_WARN(sc, "Support for RF2425 is under development.\n");
|
||||
}
|
||||
|
||||
/* Identify single chip solutions */
|
||||
if (((srev <= AR5K_SREV_VER_AR5414) &&
|
||||
(srev >= AR5K_SREV_VER_AR2413)) ||
|
||||
(srev == AR5K_SREV_VER_AR2425)) {
|
||||
ah->ah_single_chip = true;
|
||||
} else {
|
||||
ah->ah_single_chip = false;
|
||||
}
|
||||
|
||||
/* Single chip radio */
|
||||
if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision)
|
||||
ah->ah_radio_2ghz_revision = 0;
|
||||
|
||||
/* Identify the radio chip*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ah->ah_radio = AR5K_RF5110;
|
||||
/*
|
||||
* Register returns 0x0/0x04 for radio revision
|
||||
* so ath5k_hw_radio_revision doesn't parse the value
|
||||
* correctly. For now we are based on mac's srev to
|
||||
* identify RF2425 radio.
|
||||
*/
|
||||
} else if (srev == AR5K_SREV_VER_AR2425) {
|
||||
ah->ah_radio = AR5K_RF2425;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
|
||||
ah->ah_radio = AR5K_RF5111;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
|
||||
ah->ah_radio = AR5K_RF5112;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
|
||||
ah->ah_radio = AR5K_RF2413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
|
||||
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
|
||||
/* AR5424 */
|
||||
if (srev >= AR5K_SREV_VER_AR5424) {
|
||||
ah->ah_radio = AR5K_RF5413;
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
|
||||
/* AR2424 */
|
||||
} else {
|
||||
ah->ah_radio = AR5K_RF2413; /* For testing */
|
||||
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
|
||||
}
|
||||
}
|
||||
ah->ah_phy = AR5K_PHY(0);
|
||||
|
||||
/*
|
||||
* Write PCI-E power save settings
|
||||
*/
|
||||
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
|
||||
ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x24924924, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x28000039, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x53160824, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0xe5980579, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x001defff, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x1aaabe40, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0xbe105554, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x000e3007, 0x4080);
|
||||
ath5k_hw_reg_write(ah, 0x00000000, 0x4084);
|
||||
}
|
||||
|
||||
/*
|
||||
* POST
|
||||
*/
|
||||
ret = ath5k_hw_post(ah);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
/* Write AR5K_PCICFG_UNK on 2112B and later chips */
|
||||
if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B ||
|
||||
srev > AR5K_SREV_VER_AR2413) {
|
||||
ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get card capabilities, values, ...
|
||||
*/
|
||||
ret = ath5k_eeprom_init(ah);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "unable to init EEPROM\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* Get misc capabilities */
|
||||
ret = ath5k_hw_set_capabilities(ah);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
|
||||
sc->pdev->device);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/* Get MAC address */
|
||||
ret = ath5k_eeprom_read_mac(ah, mac);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
|
||||
sc->pdev->device);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ath5k_hw_set_lladdr(ah, mac);
|
||||
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
|
||||
memset(ah->ah_bssid, 0xff, ETH_ALEN);
|
||||
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
|
||||
ath5k_hw_set_opmode(ah);
|
||||
|
||||
ath5k_hw_set_rfgain_opt(ah);
|
||||
|
||||
return ah;
|
||||
err_free:
|
||||
kfree(ah);
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_detach - Free the ath5k_hw struct
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
void ath5k_hw_detach(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
|
||||
|
||||
if (ah->ah_rf_banks != NULL)
|
||||
kfree(ah->ah_rf_banks);
|
||||
|
||||
/* assume interrupts are down */
|
||||
kfree(ah);
|
||||
}
|
|
@ -485,6 +485,12 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|||
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT);
|
||||
|
||||
hw->extra_tx_headroom = 2;
|
||||
hw->channel_change_time = 5000;
|
||||
sc = hw->priv;
|
||||
|
@ -707,7 +713,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
|
|||
* return false w/o doing anything. MAC's that do
|
||||
* support it will return true w/o doing anything.
|
||||
*/
|
||||
ret = ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
|
||||
ret = ah->ah_setup_mrr_tx_desc(ah, NULL, 0, 0, 0, 0, 0, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (ret > 0)
|
||||
|
@ -1137,7 +1143,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
|||
ds = bf->desc;
|
||||
ds->ds_link = bf->daddr; /* link to self */
|
||||
ds->ds_data = bf->skbaddr;
|
||||
ath5k_hw_setup_rx_desc(ah, ds,
|
||||
ah->ah_setup_rx_desc(ah, ds,
|
||||
skb_tailroom(skb), /* buffer size */
|
||||
0);
|
||||
|
||||
|
@ -1188,12 +1194,12 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
|
|||
list_add_tail(&bf->list, &txq->q);
|
||||
sc->tx_stats[txq->qnum].len++;
|
||||
if (txq->link == NULL) /* is this first packet? */
|
||||
ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
|
||||
ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
|
||||
else /* no, so only link it */
|
||||
*txq->link = bf->daddr;
|
||||
|
||||
txq->link = &ds->ds_link;
|
||||
ath5k_hw_tx_start(ah, txq->qnum);
|
||||
ath5k_hw_start_tx_dma(ah, txq->qnum);
|
||||
mmiowb();
|
||||
spin_unlock_bh(&txq->lock);
|
||||
|
||||
|
@ -1393,7 +1399,7 @@ ath5k_beaconq_config(struct ath5k_softc *sc)
|
|||
"beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n",
|
||||
qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max);
|
||||
|
||||
ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
|
||||
ret = ath5k_hw_set_tx_queueprops(ah, sc->bhalq, &qi);
|
||||
if (ret) {
|
||||
ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
|
||||
"hardware queue!\n", __func__);
|
||||
|
@ -1442,14 +1448,14 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
|
|||
/* don't touch the hardware if marked invalid */
|
||||
ath5k_hw_stop_tx_dma(ah, sc->bhalq);
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
|
||||
ath5k_hw_get_tx_buf(ah, sc->bhalq));
|
||||
ath5k_hw_get_txdp(ah, sc->bhalq));
|
||||
for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
|
||||
if (sc->txqs[i].setup) {
|
||||
ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
|
||||
"link %p\n",
|
||||
sc->txqs[i].qnum,
|
||||
ath5k_hw_get_tx_buf(ah,
|
||||
ath5k_hw_get_txdp(ah,
|
||||
sc->txqs[i].qnum),
|
||||
sc->txqs[i].link);
|
||||
}
|
||||
|
@ -1509,8 +1515,8 @@ ath5k_rx_start(struct ath5k_softc *sc)
|
|||
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
|
||||
spin_unlock_bh(&sc->rxbuflock);
|
||||
|
||||
ath5k_hw_put_rx_buf(ah, bf->daddr);
|
||||
ath5k_hw_start_rx(ah); /* enable recv descriptors */
|
||||
ath5k_hw_set_rxdp(ah, bf->daddr);
|
||||
ath5k_hw_start_rx_dma(ah); /* enable recv descriptors */
|
||||
ath5k_mode_setup(sc); /* set filters, etc. */
|
||||
ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */
|
||||
|
||||
|
@ -1527,7 +1533,7 @@ ath5k_rx_stop(struct ath5k_softc *sc)
|
|||
{
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
|
||||
ath5k_hw_stop_pcu_recv(ah); /* disable PCU */
|
||||
ath5k_hw_stop_rx_pcu(ah); /* disable PCU */
|
||||
ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */
|
||||
ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
|
||||
|
||||
|
@ -1976,8 +1982,8 @@ ath5k_beacon_send(struct ath5k_softc *sc)
|
|||
/* NB: hw still stops DMA, so proceed */
|
||||
}
|
||||
|
||||
ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
|
||||
ath5k_hw_tx_start(ah, sc->bhalq);
|
||||
ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr);
|
||||
ath5k_hw_start_tx_dma(ah, sc->bhalq);
|
||||
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
|
||||
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
|
||||
|
||||
|
@ -2106,7 +2112,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
|
|||
{
|
||||
struct ath5k_hw *ah = sc->ah;
|
||||
|
||||
ath5k_hw_set_intr(ah, 0);
|
||||
ath5k_hw_set_imr(ah, 0);
|
||||
sc->bmisscount = 0;
|
||||
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
|
||||
|
||||
|
@ -2132,7 +2138,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
|
|||
}
|
||||
/* TODO else AP */
|
||||
|
||||
ath5k_hw_set_intr(ah, sc->imask);
|
||||
ath5k_hw_set_imr(ah, sc->imask);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2211,7 +2217,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
|
|||
|
||||
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
|
||||
ath5k_led_off(sc);
|
||||
ath5k_hw_set_intr(ah, 0);
|
||||
ath5k_hw_set_imr(ah, 0);
|
||||
synchronize_irq(sc->pdev->irq);
|
||||
}
|
||||
ath5k_txq_cleanup(sc);
|
||||
|
@ -2604,7 +2610,7 @@ ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel)
|
|||
ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
|
||||
|
||||
if (stop) {
|
||||
ath5k_hw_set_intr(ah, 0);
|
||||
ath5k_hw_set_imr(ah, 0);
|
||||
ath5k_txq_cleanup(sc);
|
||||
ath5k_rx_stop(sc);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/**************\
|
||||
* Capabilities *
|
||||
\**************/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Fill the capabilities struct
|
||||
* TODO: Merge this with EEPROM code when we are done with it
|
||||
*/
|
||||
int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
|
||||
{
|
||||
u16 ee_header;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
/* Capabilities stored in the EEPROM */
|
||||
ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
/*
|
||||
* Set radio capabilities
|
||||
* (The AR5110 only supports the middle 5GHz band)
|
||||
*/
|
||||
ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
|
||||
ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_min = 0;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_max = 0;
|
||||
|
||||
/* Set supported modes */
|
||||
__set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
|
||||
} else {
|
||||
/*
|
||||
* XXX The tranceiver supports frequencies from 4920 to 6100GHz
|
||||
* XXX and from 2312 to 2732GHz. There are problems with the
|
||||
* XXX current ieee80211 implementation because the IEEE
|
||||
* XXX channel mapping does not support negative channel
|
||||
* XXX numbers (2312MHz is channel -19). Of course, this
|
||||
* XXX doesn't matter because these channels are out of range
|
||||
* XXX but some regulation domains like MKK (Japan) will
|
||||
* XXX support frequencies somewhere around 4.8GHz.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set radio capabilities
|
||||
*/
|
||||
|
||||
if (AR5K_EEPROM_HDR_11A(ee_header)) {
|
||||
/* 4920 */
|
||||
ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
|
||||
ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
|
||||
|
||||
/* Set supported modes */
|
||||
__set_bit(AR5K_MODE_11A,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
__set_bit(AR5K_MODE_11A_TURBO,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
__set_bit(AR5K_MODE_11G_TURBO,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
}
|
||||
|
||||
/* Enable 802.11b if a 2GHz capable radio (2111/5112) is
|
||||
* connected */
|
||||
if (AR5K_EEPROM_HDR_11B(ee_header) ||
|
||||
AR5K_EEPROM_HDR_11G(ee_header)) {
|
||||
/* 2312 */
|
||||
ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
|
||||
ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
|
||||
|
||||
if (AR5K_EEPROM_HDR_11B(ee_header))
|
||||
__set_bit(AR5K_MODE_11B,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
|
||||
if (AR5K_EEPROM_HDR_11G(ee_header))
|
||||
__set_bit(AR5K_MODE_11G,
|
||||
ah->ah_capabilities.cap_mode);
|
||||
}
|
||||
}
|
||||
|
||||
/* GPIO */
|
||||
ah->ah_gpio_npins = AR5K_NUM_GPIO;
|
||||
|
||||
/* Set number of supported TX queues */
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ah->ah_capabilities.cap_queues.q_tx_num =
|
||||
AR5K_NUM_TX_QUEUES_NOQCU;
|
||||
else
|
||||
ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main function used by the driver part to check caps */
|
||||
int ath5k_hw_get_capability(struct ath5k_hw *ah,
|
||||
enum ath5k_capability_type cap_type,
|
||||
u32 capability, u32 *result)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
switch (cap_type) {
|
||||
case AR5K_CAP_NUM_TXQUEUES:
|
||||
if (result) {
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
*result = AR5K_NUM_TX_QUEUES_NOQCU;
|
||||
else
|
||||
*result = AR5K_NUM_TX_QUEUES;
|
||||
goto yes;
|
||||
}
|
||||
case AR5K_CAP_VEOL:
|
||||
goto yes;
|
||||
case AR5K_CAP_COMPRESSION:
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
goto yes;
|
||||
else
|
||||
goto no;
|
||||
case AR5K_CAP_BURST:
|
||||
goto yes;
|
||||
case AR5K_CAP_TPC:
|
||||
goto yes;
|
||||
case AR5K_CAP_BSSIDMASK:
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
goto yes;
|
||||
else
|
||||
goto no;
|
||||
case AR5K_CAP_XR:
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
goto yes;
|
||||
else
|
||||
goto no;
|
||||
default:
|
||||
goto no;
|
||||
}
|
||||
|
||||
no:
|
||||
return -EINVAL;
|
||||
yes:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Following functions should be part of a new function
|
||||
* set_capability
|
||||
*/
|
||||
|
||||
int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
|
||||
u16 assoc_id)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
|
||||
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
|
||||
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
|
@ -58,8 +58,8 @@
|
|||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
#include "debug.h"
|
||||
|
||||
static unsigned int ath5k_debug;
|
||||
module_param_named(debug, ath5k_debug, uint, 0);
|
||||
|
@ -525,7 +525,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
|
|||
return;
|
||||
|
||||
printk(KERN_DEBUG "rx queue %x, link %p\n",
|
||||
ath5k_hw_get_rx_buf(ah), sc->rxlink);
|
||||
ath5k_hw_get_rxdp(ah), sc->rxlink);
|
||||
|
||||
spin_lock_bh(&sc->rxbuflock);
|
||||
list_for_each_entry(bf, &sc->rxbuf, list) {
|
||||
|
|
|
@ -0,0 +1,667 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************\
|
||||
Hardware Descriptor Functions
|
||||
\******************************/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* TX Descriptors
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize the 2-word tx control descriptor on 5210/5211
|
||||
*/
|
||||
static int
|
||||
ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||
unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
|
||||
unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
|
||||
unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
|
||||
unsigned int rtscts_rate, unsigned int rtscts_duration)
|
||||
{
|
||||
u32 frame_type;
|
||||
struct ath5k_hw_2w_tx_ctl *tx_ctl;
|
||||
unsigned int frame_len;
|
||||
|
||||
tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
|
||||
|
||||
/*
|
||||
* Validate input
|
||||
* - Zero retries don't make sense.
|
||||
* - A zero rate will put the HW into a mode where it continously sends
|
||||
* noise on the channel, so it is important to avoid this.
|
||||
*/
|
||||
if (unlikely(tx_tries0 == 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "zero retries\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (unlikely(tx_rate0 == 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "zero rate\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear descriptor */
|
||||
memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
|
||||
|
||||
/* Setup control descriptor */
|
||||
|
||||
/* Verify and set frame length */
|
||||
|
||||
/* remove padding we might have added before */
|
||||
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
|
||||
|
||||
if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
|
||||
|
||||
/* Verify and set buffer length */
|
||||
|
||||
/* NB: beacon's BufLen must be a multiple of 4 bytes */
|
||||
if (type == AR5K_PKT_TYPE_BEACON)
|
||||
pkt_len = roundup(pkt_len, 4);
|
||||
|
||||
if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
|
||||
|
||||
/*
|
||||
* Verify and set header length
|
||||
* XXX: I only found that on 5210 code, does it work on 5211 ?
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
|
||||
return -EINVAL;
|
||||
tx_ctl->tx_control_0 |=
|
||||
AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
|
||||
}
|
||||
|
||||
/*Diferences between 5210-5211*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
switch (type) {
|
||||
case AR5K_PKT_TYPE_BEACON:
|
||||
case AR5K_PKT_TYPE_PROBE_RESP:
|
||||
frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
|
||||
case AR5K_PKT_TYPE_PIFS:
|
||||
frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
|
||||
default:
|
||||
frame_type = type /*<< 2 ?*/;
|
||||
}
|
||||
|
||||
tx_ctl->tx_control_0 |=
|
||||
AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
|
||||
AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
|
||||
|
||||
} else {
|
||||
tx_ctl->tx_control_0 |=
|
||||
AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
|
||||
AR5K_REG_SM(antenna_mode,
|
||||
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
|
||||
tx_ctl->tx_control_1 |=
|
||||
AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
|
||||
}
|
||||
#define _TX_FLAGS(_c, _flag) \
|
||||
if (flags & AR5K_TXDESC_##_flag) { \
|
||||
tx_ctl->tx_control_##_c |= \
|
||||
AR5K_2W_TX_DESC_CTL##_c##_##_flag; \
|
||||
}
|
||||
|
||||
_TX_FLAGS(0, CLRDMASK);
|
||||
_TX_FLAGS(0, VEOL);
|
||||
_TX_FLAGS(0, INTREQ);
|
||||
_TX_FLAGS(0, RTSENA);
|
||||
_TX_FLAGS(1, NOACK);
|
||||
|
||||
#undef _TX_FLAGS
|
||||
|
||||
/*
|
||||
* WEP crap
|
||||
*/
|
||||
if (key_index != AR5K_TXKEYIX_INVALID) {
|
||||
tx_ctl->tx_control_0 |=
|
||||
AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
|
||||
tx_ctl->tx_control_1 |=
|
||||
AR5K_REG_SM(key_index,
|
||||
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTS/CTS Duration [5210 ?]
|
||||
*/
|
||||
if ((ah->ah_version == AR5K_AR5210) &&
|
||||
(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
|
||||
tx_ctl->tx_control_1 |= rtscts_duration &
|
||||
AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the 4-word tx control descriptor on 5212
|
||||
*/
|
||||
static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
|
||||
struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
|
||||
enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
|
||||
unsigned int tx_tries0, unsigned int key_index,
|
||||
unsigned int antenna_mode, unsigned int flags,
|
||||
unsigned int rtscts_rate,
|
||||
unsigned int rtscts_duration)
|
||||
{
|
||||
struct ath5k_hw_4w_tx_ctl *tx_ctl;
|
||||
unsigned int frame_len;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
|
||||
|
||||
/*
|
||||
* Validate input
|
||||
* - Zero retries don't make sense.
|
||||
* - A zero rate will put the HW into a mode where it continously sends
|
||||
* noise on the channel, so it is important to avoid this.
|
||||
*/
|
||||
if (unlikely(tx_tries0 == 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "zero retries\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (unlikely(tx_rate0 == 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "zero rate\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear descriptor */
|
||||
memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
|
||||
|
||||
/* Setup control descriptor */
|
||||
|
||||
/* Verify and set frame length */
|
||||
|
||||
/* remove padding we might have added before */
|
||||
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
|
||||
|
||||
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
|
||||
|
||||
/* Verify and set buffer length */
|
||||
|
||||
/* NB: beacon's BufLen must be a multiple of 4 bytes */
|
||||
if (type == AR5K_PKT_TYPE_BEACON)
|
||||
pkt_len = roundup(pkt_len, 4);
|
||||
|
||||
if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
|
||||
|
||||
tx_ctl->tx_control_0 |=
|
||||
AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
|
||||
AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
|
||||
tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
|
||||
AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
|
||||
tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
|
||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
|
||||
tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
|
||||
|
||||
#define _TX_FLAGS(_c, _flag) \
|
||||
if (flags & AR5K_TXDESC_##_flag) { \
|
||||
tx_ctl->tx_control_##_c |= \
|
||||
AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
|
||||
}
|
||||
|
||||
_TX_FLAGS(0, CLRDMASK);
|
||||
_TX_FLAGS(0, VEOL);
|
||||
_TX_FLAGS(0, INTREQ);
|
||||
_TX_FLAGS(0, RTSENA);
|
||||
_TX_FLAGS(0, CTSENA);
|
||||
_TX_FLAGS(1, NOACK);
|
||||
|
||||
#undef _TX_FLAGS
|
||||
|
||||
/*
|
||||
* WEP crap
|
||||
*/
|
||||
if (key_index != AR5K_TXKEYIX_INVALID) {
|
||||
tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
|
||||
tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index,
|
||||
AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTS/CTS
|
||||
*/
|
||||
if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
|
||||
if ((flags & AR5K_TXDESC_RTSENA) &&
|
||||
(flags & AR5K_TXDESC_CTSENA))
|
||||
return -EINVAL;
|
||||
tx_ctl->tx_control_2 |= rtscts_duration &
|
||||
AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
|
||||
tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
|
||||
AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a 4-word multi rate retry tx control descriptor on 5212
|
||||
*/
|
||||
static int
|
||||
ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||
unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
|
||||
u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3)
|
||||
{
|
||||
struct ath5k_hw_4w_tx_ctl *tx_ctl;
|
||||
|
||||
/*
|
||||
* Rates can be 0 as long as the retry count is 0 too.
|
||||
* A zero rate and nonzero retry count will put the HW into a mode where
|
||||
* it continously sends noise on the channel, so it is important to
|
||||
* avoid this.
|
||||
*/
|
||||
if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
|
||||
(tx_rate2 == 0 && tx_tries2 != 0) ||
|
||||
(tx_rate3 == 0 && tx_tries3 != 0))) {
|
||||
ATH5K_ERR(ah->ah_sc, "zero rate\n");
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
|
||||
|
||||
#define _XTX_TRIES(_n) \
|
||||
if (tx_tries##_n) { \
|
||||
tx_ctl->tx_control_2 |= \
|
||||
AR5K_REG_SM(tx_tries##_n, \
|
||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \
|
||||
tx_ctl->tx_control_3 |= \
|
||||
AR5K_REG_SM(tx_rate##_n, \
|
||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \
|
||||
}
|
||||
|
||||
_XTX_TRIES(1);
|
||||
_XTX_TRIES(2);
|
||||
_XTX_TRIES(3);
|
||||
|
||||
#undef _XTX_TRIES
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Proccess the tx status descriptor on 5210/5211
|
||||
*/
|
||||
static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
|
||||
struct ath5k_desc *desc, struct ath5k_tx_status *ts)
|
||||
{
|
||||
struct ath5k_hw_2w_tx_ctl *tx_ctl;
|
||||
struct ath5k_hw_tx_status *tx_status;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
|
||||
tx_status = &desc->ud.ds_tx5210.tx_stat;
|
||||
|
||||
/* No frame has been send or error */
|
||||
if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
|
||||
return -EINPROGRESS;
|
||||
|
||||
/*
|
||||
* Get descriptor status
|
||||
*/
|
||||
ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
|
||||
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
|
||||
ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
|
||||
/*TODO: ts->ts_virtcol + test*/
|
||||
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
|
||||
AR5K_DESC_TX_STATUS1_SEQ_NUM);
|
||||
ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
|
||||
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
|
||||
ts->ts_antenna = 1;
|
||||
ts->ts_status = 0;
|
||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0,
|
||||
AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
|
||||
|
||||
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
|
||||
if (tx_status->tx_status_0 &
|
||||
AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
|
||||
ts->ts_status |= AR5K_TXERR_XRETRY;
|
||||
|
||||
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
|
||||
ts->ts_status |= AR5K_TXERR_FIFO;
|
||||
|
||||
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
|
||||
ts->ts_status |= AR5K_TXERR_FILT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Proccess a tx status descriptor on 5212
|
||||
*/
|
||||
static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
|
||||
struct ath5k_desc *desc, struct ath5k_tx_status *ts)
|
||||
{
|
||||
struct ath5k_hw_4w_tx_ctl *tx_ctl;
|
||||
struct ath5k_hw_tx_status *tx_status;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
|
||||
tx_status = &desc->ud.ds_tx5212.tx_stat;
|
||||
|
||||
/* No frame has been send or error */
|
||||
if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
|
||||
return -EINPROGRESS;
|
||||
|
||||
/*
|
||||
* Get descriptor status
|
||||
*/
|
||||
ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
|
||||
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
|
||||
ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
|
||||
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
|
||||
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
|
||||
AR5K_DESC_TX_STATUS1_SEQ_NUM);
|
||||
ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
|
||||
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
|
||||
ts->ts_antenna = (tx_status->tx_status_1 &
|
||||
AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
|
||||
ts->ts_status = 0;
|
||||
|
||||
switch (AR5K_REG_MS(tx_status->tx_status_1,
|
||||
AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
|
||||
case 0:
|
||||
ts->ts_rate = tx_ctl->tx_control_3 &
|
||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
|
||||
break;
|
||||
case 1:
|
||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
|
||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
|
||||
break;
|
||||
case 2:
|
||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
|
||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
|
||||
break;
|
||||
case 3:
|
||||
ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3,
|
||||
AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
|
||||
ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2,
|
||||
AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
|
||||
break;
|
||||
}
|
||||
|
||||
/* TX error */
|
||||
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
|
||||
if (tx_status->tx_status_0 &
|
||||
AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
|
||||
ts->ts_status |= AR5K_TXERR_XRETRY;
|
||||
|
||||
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
|
||||
ts->ts_status |= AR5K_TXERR_FIFO;
|
||||
|
||||
if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
|
||||
ts->ts_status |= AR5K_TXERR_FILT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* RX Descriptors
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize an rx control descriptor
|
||||
*/
|
||||
static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
|
||||
u32 size, unsigned int flags)
|
||||
{
|
||||
struct ath5k_hw_rx_ctl *rx_ctl;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
rx_ctl = &desc->ud.ds_rx.rx_ctl;
|
||||
|
||||
/*
|
||||
* Clear the descriptor
|
||||
* If we don't clean the status descriptor,
|
||||
* while scanning we get too many results,
|
||||
* most of them virtual, after some secs
|
||||
* of scanning system hangs. M.F.
|
||||
*/
|
||||
memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
|
||||
|
||||
/* Setup descriptor */
|
||||
rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
|
||||
if (unlikely(rx_ctl->rx_control_1 != size))
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & AR5K_RXDESC_INTREQ)
|
||||
rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Proccess the rx status descriptor on 5210/5211
|
||||
*/
|
||||
static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
|
||||
struct ath5k_desc *desc, struct ath5k_rx_status *rs)
|
||||
{
|
||||
struct ath5k_hw_rx_status *rx_status;
|
||||
|
||||
rx_status = &desc->ud.ds_rx.u.rx_stat;
|
||||
|
||||
/* No frame received / not ready */
|
||||
if (unlikely(!(rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_DONE)))
|
||||
return -EINPROGRESS;
|
||||
|
||||
/*
|
||||
* Frame receive status
|
||||
*/
|
||||
rs->rs_datalen = rx_status->rx_status_0 &
|
||||
AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
|
||||
rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
|
||||
AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
|
||||
rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
|
||||
AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
|
||||
rs->rs_antenna = rx_status->rx_status_0 &
|
||||
AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA;
|
||||
rs->rs_more = rx_status->rx_status_0 &
|
||||
AR5K_5210_RX_DESC_STATUS0_MORE;
|
||||
/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
|
||||
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
|
||||
AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
|
||||
rs->rs_status = 0;
|
||||
rs->rs_phyerr = 0;
|
||||
|
||||
/*
|
||||
* Key table status
|
||||
*/
|
||||
if (rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID)
|
||||
rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
|
||||
AR5K_5210_RX_DESC_STATUS1_KEY_INDEX);
|
||||
else
|
||||
rs->rs_keyix = AR5K_RXKEYIX_INVALID;
|
||||
|
||||
/*
|
||||
* Receive/descriptor errors
|
||||
*/
|
||||
if (!(rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
|
||||
rs->rs_status |= AR5K_RXERR_CRC;
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
|
||||
rs->rs_status |= AR5K_RXERR_FIFO;
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
|
||||
rs->rs_status |= AR5K_RXERR_PHY;
|
||||
rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
|
||||
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
|
||||
}
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
|
||||
rs->rs_status |= AR5K_RXERR_DECRYPT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Proccess the rx status descriptor on 5212
|
||||
*/
|
||||
static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
|
||||
struct ath5k_desc *desc, struct ath5k_rx_status *rs)
|
||||
{
|
||||
struct ath5k_hw_rx_status *rx_status;
|
||||
struct ath5k_hw_rx_error *rx_err;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
rx_status = &desc->ud.ds_rx.u.rx_stat;
|
||||
|
||||
/* Overlay on error */
|
||||
rx_err = &desc->ud.ds_rx.u.rx_err;
|
||||
|
||||
/* No frame received / not ready */
|
||||
if (unlikely(!(rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_DONE)))
|
||||
return -EINPROGRESS;
|
||||
|
||||
/*
|
||||
* Frame receive status
|
||||
*/
|
||||
rs->rs_datalen = rx_status->rx_status_0 &
|
||||
AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
|
||||
rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
|
||||
AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
|
||||
rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
|
||||
AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
|
||||
rs->rs_antenna = rx_status->rx_status_0 &
|
||||
AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA;
|
||||
rs->rs_more = rx_status->rx_status_0 &
|
||||
AR5K_5212_RX_DESC_STATUS0_MORE;
|
||||
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
|
||||
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
|
||||
rs->rs_status = 0;
|
||||
rs->rs_phyerr = 0;
|
||||
|
||||
/*
|
||||
* Key table status
|
||||
*/
|
||||
if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
|
||||
rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
|
||||
AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
|
||||
else
|
||||
rs->rs_keyix = AR5K_RXKEYIX_INVALID;
|
||||
|
||||
/*
|
||||
* Receive/descriptor errors
|
||||
*/
|
||||
if (!(rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
|
||||
rs->rs_status |= AR5K_RXERR_CRC;
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
|
||||
rs->rs_status |= AR5K_RXERR_PHY;
|
||||
rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
|
||||
AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
|
||||
}
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
|
||||
rs->rs_status |= AR5K_RXERR_DECRYPT;
|
||||
|
||||
if (rx_status->rx_status_1 &
|
||||
AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
|
||||
rs->rs_status |= AR5K_RXERR_MIC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init function pointers inside ath5k_hw struct
|
||||
*/
|
||||
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
|
||||
{
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210 &&
|
||||
ah->ah_version != AR5K_AR5211 &&
|
||||
ah->ah_version != AR5K_AR5212)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* XXX: What is this magic value and where is it used ? */
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
|
||||
else if (ah->ah_version == AR5K_AR5211)
|
||||
ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
|
||||
ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
|
||||
ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
|
||||
ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
|
||||
} else {
|
||||
ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
|
||||
ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
|
||||
ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc;
|
||||
ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
|
||||
}
|
||||
|
||||
if (ah->ah_version == AR5K_AR5212)
|
||||
ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
|
||||
else if (ah->ah_version <= AR5K_AR5211)
|
||||
ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org>
|
||||
* Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -15,159 +13,9 @@
|
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
/*
|
||||
* Gain settings
|
||||
*/
|
||||
|
||||
enum ath5k_rfgain {
|
||||
AR5K_RFGAIN_INACTIVE = 0,
|
||||
AR5K_RFGAIN_READ_REQUESTED,
|
||||
AR5K_RFGAIN_NEED_CHANGE,
|
||||
};
|
||||
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5111 4
|
||||
#define AR5K_GAIN_CRN_FIX_BITS_5112 7
|
||||
#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112
|
||||
#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15
|
||||
#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20
|
||||
#define AR5K_GAIN_CCK_PROBE_CORR 5
|
||||
#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15
|
||||
#define AR5K_GAIN_STEP_COUNT 10
|
||||
#define AR5K_GAIN_PARAM_TX_CLIP 0
|
||||
#define AR5K_GAIN_PARAM_PD_90 1
|
||||
#define AR5K_GAIN_PARAM_PD_84 2
|
||||
#define AR5K_GAIN_PARAM_GAIN_SEL 3
|
||||
#define AR5K_GAIN_PARAM_MIX_ORN 0
|
||||
#define AR5K_GAIN_PARAM_PD_138 1
|
||||
#define AR5K_GAIN_PARAM_PD_137 2
|
||||
#define AR5K_GAIN_PARAM_PD_136 3
|
||||
#define AR5K_GAIN_PARAM_PD_132 4
|
||||
#define AR5K_GAIN_PARAM_PD_131 5
|
||||
#define AR5K_GAIN_PARAM_PD_130 6
|
||||
#define AR5K_GAIN_CHECK_ADJUST(_g) \
|
||||
((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
|
||||
|
||||
struct ath5k_gain_opt_step {
|
||||
s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
|
||||
s32 gos_gain;
|
||||
};
|
||||
|
||||
struct ath5k_gain {
|
||||
u32 g_step_idx;
|
||||
u32 g_current;
|
||||
u32 g_target;
|
||||
u32 g_low;
|
||||
u32 g_high;
|
||||
u32 g_f_corr;
|
||||
u32 g_active;
|
||||
const struct ath5k_gain_opt_step *g_step;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* HW SPECIFIC STRUCTS
|
||||
*/
|
||||
|
||||
/* Some EEPROM defines */
|
||||
#define AR5K_EEPROM_EEP_SCALE 100
|
||||
#define AR5K_EEPROM_EEP_DELTA 10
|
||||
#define AR5K_EEPROM_N_MODES 3
|
||||
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
||||
#define AR5K_EEPROM_MAX_CHAN 10
|
||||
#define AR5K_EEPROM_N_PCDAC 11
|
||||
#define AR5K_EEPROM_N_TEST_FREQ 8
|
||||
#define AR5K_EEPROM_N_EDGES 8
|
||||
#define AR5K_EEPROM_N_INTERCEPTS 11
|
||||
#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
|
||||
#define AR5K_EEPROM_PCDAC_M 0x3f
|
||||
#define AR5K_EEPROM_PCDAC_START 1
|
||||
#define AR5K_EEPROM_PCDAC_STOP 63
|
||||
#define AR5K_EEPROM_PCDAC_STEP 1
|
||||
#define AR5K_EEPROM_NON_EDGE_M 0x40
|
||||
#define AR5K_EEPROM_CHANNEL_POWER 8
|
||||
#define AR5K_EEPROM_N_OBDB 4
|
||||
#define AR5K_EEPROM_OBDB_DIS 0xffff
|
||||
#define AR5K_EEPROM_CHANNEL_DIS 0xff
|
||||
#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10)
|
||||
#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32)
|
||||
#define AR5K_EEPROM_MAX_CTLS 32
|
||||
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
|
||||
#define AR5K_EEPROM_N_XPD0_POINTS 4
|
||||
#define AR5K_EEPROM_N_XPD3_POINTS 3
|
||||
#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35
|
||||
#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
|
||||
#define AR5K_EEPROM_POWER_M 0x3f
|
||||
#define AR5K_EEPROM_POWER_MIN 0
|
||||
#define AR5K_EEPROM_POWER_MAX 3150
|
||||
#define AR5K_EEPROM_POWER_STEP 50
|
||||
#define AR5K_EEPROM_POWER_TABLE_SIZE 64
|
||||
#define AR5K_EEPROM_N_POWER_LOC_11B 4
|
||||
#define AR5K_EEPROM_N_POWER_LOC_11G 6
|
||||
#define AR5K_EEPROM_I_GAIN 10
|
||||
#define AR5K_EEPROM_CCK_OFDM_DELTA 15
|
||||
#define AR5K_EEPROM_N_IQ_CAL 2
|
||||
|
||||
/* Struct to hold EEPROM calibration data */
|
||||
struct ath5k_eeprom_info {
|
||||
u16 ee_magic;
|
||||
u16 ee_protect;
|
||||
u16 ee_regdomain;
|
||||
u16 ee_version;
|
||||
u16 ee_header;
|
||||
u16 ee_ant_gain;
|
||||
u16 ee_misc0;
|
||||
u16 ee_misc1;
|
||||
u16 ee_cck_ofdm_gain_delta;
|
||||
u16 ee_cck_ofdm_power_delta;
|
||||
u16 ee_scaled_cck_delta;
|
||||
|
||||
/* Used for tx thermal adjustment (eeprom_init, rfregs) */
|
||||
u16 ee_tx_clip;
|
||||
u16 ee_pwd_84;
|
||||
u16 ee_pwd_90;
|
||||
u16 ee_gain_select;
|
||||
|
||||
/* RF Calibration settings (reset, rfregs) */
|
||||
u16 ee_i_cal[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_q_cal[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_fixed_bias[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xr_power[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_switch_settling[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
|
||||
u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
|
||||
u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
|
||||
u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_thr_62[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xlna_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xpd[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_x_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_i_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
|
||||
|
||||
/* Unused */
|
||||
u16 ee_false_detect[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
|
||||
|
||||
/* Conformance test limits (Unused) */
|
||||
u16 ee_ctls;
|
||||
u16 ee_ctl[AR5K_EEPROM_MAX_CTLS];
|
||||
|
||||
/* Noise Floor Calibration settings */
|
||||
s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
|
||||
s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES];
|
||||
s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES];
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal RX/TX descriptor structures
|
||||
* (rX: reserved fields possibily used by future versions of the ar5k chipset)
|
||||
|
@ -178,14 +26,15 @@ struct ath5k_eeprom_info {
|
|||
*/
|
||||
struct ath5k_hw_rx_ctl {
|
||||
u32 rx_control_0; /* RX control word 0 */
|
||||
u32 rx_control_1; /* RX control word 1 */
|
||||
} __packed;
|
||||
|
||||
/* RX control word 0 field/sflags */
|
||||
#define AR5K_DESC_RX_CTL0 0x00000000
|
||||
|
||||
u32 rx_control_1; /* RX control word 1 */
|
||||
|
||||
/* RX control word 1 fields/flags */
|
||||
#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff
|
||||
#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* common hardware RX status descriptor
|
||||
|
@ -197,6 +46,7 @@ struct ath5k_hw_rx_status {
|
|||
} __packed;
|
||||
|
||||
/* 5210/5211 */
|
||||
/* RX status word 0 fields/flags */
|
||||
#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN 0x00000fff
|
||||
#define AR5K_5210_RX_DESC_STATUS0_MORE 0x00001000
|
||||
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000
|
||||
|
@ -205,6 +55,8 @@ struct ath5k_hw_rx_status {
|
|||
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19
|
||||
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000
|
||||
#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27
|
||||
|
||||
/* RX status word 1 fields/flags */
|
||||
#define AR5K_5210_RX_DESC_STATUS1_DONE 0x00000001
|
||||
#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
|
||||
#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR 0x00000004
|
||||
|
@ -220,6 +72,7 @@ struct ath5k_hw_rx_status {
|
|||
#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000
|
||||
|
||||
/* 5212 */
|
||||
/* RX status word 0 fields/flags */
|
||||
#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN 0x00000fff
|
||||
#define AR5K_5212_RX_DESC_STATUS0_MORE 0x00001000
|
||||
#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000
|
||||
|
@ -229,6 +82,8 @@ struct ath5k_hw_rx_status {
|
|||
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20
|
||||
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000
|
||||
#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28
|
||||
|
||||
/* RX status word 1 fields/flags */
|
||||
#define AR5K_5212_RX_DESC_STATUS1_DONE 0x00000001
|
||||
#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002
|
||||
#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR 0x00000004
|
||||
|
@ -246,16 +101,18 @@ struct ath5k_hw_rx_status {
|
|||
* common hardware RX error descriptor
|
||||
*/
|
||||
struct ath5k_hw_rx_error {
|
||||
u32 rx_error_0; /* RX error word 0 */
|
||||
|
||||
#define AR5K_RX_DESC_ERROR0 0x00000000
|
||||
|
||||
u32 rx_error_1; /* RX error word 1 */
|
||||
|
||||
#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00
|
||||
#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8
|
||||
u32 rx_error_0; /* RX status word 0 */
|
||||
u32 rx_error_1; /* RX status word 1 */
|
||||
} __packed;
|
||||
|
||||
/* RX error word 0 fields/flags */
|
||||
#define AR5K_RX_DESC_ERROR0 0x00000000
|
||||
|
||||
/* RX error word 1 fields/flags */
|
||||
#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00
|
||||
#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8
|
||||
|
||||
/* PHY Error codes */
|
||||
#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00
|
||||
#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20
|
||||
#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40
|
||||
|
@ -270,7 +127,10 @@ struct ath5k_hw_rx_error {
|
|||
*/
|
||||
struct ath5k_hw_2w_tx_ctl {
|
||||
u32 tx_control_0; /* TX control word 0 */
|
||||
u32 tx_control_1; /* TX control word 1 */
|
||||
} __packed;
|
||||
|
||||
/* TX control word 0 fields/flags */
|
||||
#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff
|
||||
#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/
|
||||
#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12
|
||||
|
@ -284,29 +144,34 @@ struct ath5k_hw_2w_tx_ctl {
|
|||
#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26
|
||||
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000
|
||||
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000
|
||||
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT (ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
|
||||
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
|
||||
|
||||
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT \
|
||||
(ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
|
||||
AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
|
||||
|
||||
#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25
|
||||
#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000
|
||||
#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000
|
||||
|
||||
u32 tx_control_1; /* TX control word 1 */
|
||||
|
||||
/* TX control word 1 fields/flags */
|
||||
#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff
|
||||
#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000
|
||||
#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000
|
||||
#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000
|
||||
#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
|
||||
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
|
||||
|
||||
#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX \
|
||||
(ah->ah_version == AR5K_AR5210 ? \
|
||||
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
|
||||
AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
|
||||
|
||||
#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13
|
||||
#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/
|
||||
#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20
|
||||
#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/
|
||||
#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/
|
||||
} __packed;
|
||||
|
||||
/* Frame types */
|
||||
#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00
|
||||
#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04
|
||||
#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08
|
||||
|
@ -378,7 +243,10 @@ struct ath5k_hw_4w_tx_ctl {
|
|||
*/
|
||||
struct ath5k_hw_tx_status {
|
||||
u32 tx_status_0; /* TX status word 0 */
|
||||
u32 tx_status_1; /* TX status word 1 */
|
||||
} __packed;
|
||||
|
||||
/* TX status word 0 fields/flags */
|
||||
#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001
|
||||
#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002
|
||||
#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004
|
||||
|
@ -400,8 +268,7 @@ struct ath5k_hw_tx_status {
|
|||
#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000
|
||||
#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16
|
||||
|
||||
u32 tx_status_1; /* TX status word 1 */
|
||||
|
||||
/* TX status word 1 fields/flags */
|
||||
#define AR5K_DESC_TX_STATUS1_DONE 0x00000001
|
||||
#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe
|
||||
#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1
|
||||
|
@ -411,8 +278,6 @@ struct ath5k_hw_tx_status {
|
|||
#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21
|
||||
#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000
|
||||
#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000
|
||||
} __packed;
|
||||
|
||||
|
||||
/*
|
||||
* 5210/5211 hardware TX descriptor
|
||||
|
@ -441,176 +306,27 @@ struct ath5k_hw_all_rx_desc {
|
|||
} u;
|
||||
} __packed;
|
||||
|
||||
|
||||
/*
|
||||
* AR5K REGISTER ACCESS
|
||||
* Atheros hardware descriptor
|
||||
* This is read and written to by the hardware
|
||||
*/
|
||||
struct ath5k_desc {
|
||||
u32 ds_link; /* physical address of the next descriptor */
|
||||
u32 ds_data; /* physical address of data buffer (skb) */
|
||||
|
||||
/*Swap RX/TX Descriptor for big endian archs*/
|
||||
#if defined(__BIG_ENDIAN)
|
||||
#define AR5K_INIT_CFG ( \
|
||||
AR5K_CFG_SWTD | AR5K_CFG_SWRD \
|
||||
)
|
||||
#else
|
||||
#define AR5K_INIT_CFG 0x00000000
|
||||
#endif
|
||||
union {
|
||||
struct ath5k_hw_5210_tx_desc ds_tx5210;
|
||||
struct ath5k_hw_5212_tx_desc ds_tx5212;
|
||||
struct ath5k_hw_all_rx_desc ds_rx;
|
||||
} ud;
|
||||
} __packed;
|
||||
|
||||
/*#define AR5K_REG_READ(_reg) ath5k_hw_reg_read(ah, _reg)
|
||||
#define AR5K_RXDESC_INTREQ 0x0020
|
||||
|
||||
#define AR5K_REG_WRITE(_reg, _val) ath5k_hw_reg_write(ah, _val, _reg)*/
|
||||
#define AR5K_TXDESC_CLRDMASK 0x0001
|
||||
#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/
|
||||
#define AR5K_TXDESC_RTSENA 0x0004
|
||||
#define AR5K_TXDESC_CTSENA 0x0008
|
||||
#define AR5K_TXDESC_INTREQ 0x0010
|
||||
#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/
|
||||
|
||||
#define AR5K_REG_SM(_val, _flags) \
|
||||
(((_val) << _flags##_S) & (_flags))
|
||||
|
||||
#define AR5K_REG_MS(_val, _flags) \
|
||||
(((_val) & (_flags)) >> _flags##_S)
|
||||
|
||||
/* Some registers can hold multiple values of interest. For this
|
||||
* reason when we want to write to these registers we must first
|
||||
* retrieve the values which we do not want to clear (lets call this
|
||||
* old_data) and then set the register with this and our new_value:
|
||||
* ( old_data | new_value) */
|
||||
#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \
|
||||
ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
|
||||
(((_val) << _flags##_S) & (_flags)), _reg)
|
||||
|
||||
#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \
|
||||
ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \
|
||||
(_mask)) | (_flags), _reg)
|
||||
|
||||
#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
|
||||
|
||||
#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
|
||||
|
||||
#define AR5K_PHY_WRITE(ah, _reg, _val) \
|
||||
ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
#define AR5K_PHY_READ(ah, _reg) \
|
||||
ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
|
||||
|
||||
#define AR5K_REG_WAIT(_i) do { \
|
||||
if (_i % 64) \
|
||||
udelay(1); \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_EEPROM_READ(_o, _v) do { \
|
||||
if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \
|
||||
return (ret); \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_EEPROM_READ_HDR(_o, _v) \
|
||||
AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \
|
||||
|
||||
/* Read status of selected queue */
|
||||
#define AR5K_REG_READ_Q(ah, _reg, _queue) \
|
||||
(ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \
|
||||
|
||||
#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \
|
||||
ath5k_hw_reg_write(ah, (1 << _queue), _reg)
|
||||
|
||||
#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \
|
||||
_reg |= 1 << _queue; \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \
|
||||
_reg &= ~(1 << _queue); \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_LOW_ID(_a)( \
|
||||
(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \
|
||||
)
|
||||
|
||||
#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8)
|
||||
|
||||
/*
|
||||
* Initial register values
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common initial register values
|
||||
*/
|
||||
#define AR5K_INIT_MODE CHANNEL_B
|
||||
|
||||
#define AR5K_INIT_TX_LATENCY 502
|
||||
#define AR5K_INIT_USEC 39
|
||||
#define AR5K_INIT_USEC_TURBO 79
|
||||
#define AR5K_INIT_USEC_32 31
|
||||
#define AR5K_INIT_CARR_SENSE_EN 1
|
||||
#define AR5K_INIT_PROG_IFS 920
|
||||
#define AR5K_INIT_PROG_IFS_TURBO 960
|
||||
#define AR5K_INIT_EIFS 3440
|
||||
#define AR5K_INIT_EIFS_TURBO 6880
|
||||
#define AR5K_INIT_SLOT_TIME 396
|
||||
#define AR5K_INIT_SLOT_TIME_TURBO 480
|
||||
#define AR5K_INIT_ACK_CTS_TIMEOUT 1024
|
||||
#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800
|
||||
#define AR5K_INIT_SIFS 560
|
||||
#define AR5K_INIT_SIFS_TURBO 480
|
||||
#define AR5K_INIT_SH_RETRY 10
|
||||
#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY
|
||||
#define AR5K_INIT_SSH_RETRY 32
|
||||
#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY
|
||||
#define AR5K_INIT_TX_RETRY 10
|
||||
#define AR5K_INIT_TOPS 8
|
||||
#define AR5K_INIT_RXNOFRM 8
|
||||
#define AR5K_INIT_RPGTO 0
|
||||
#define AR5K_INIT_TXNOFRM 0
|
||||
#define AR5K_INIT_BEACON_PERIOD 65535
|
||||
#define AR5K_INIT_TIM_OFFSET 0
|
||||
#define AR5K_INIT_BEACON_EN 0
|
||||
#define AR5K_INIT_RESET_TSF 0
|
||||
|
||||
#define AR5K_INIT_TRANSMIT_LATENCY ( \
|
||||
(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
|
||||
(AR5K_INIT_USEC) \
|
||||
)
|
||||
#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \
|
||||
(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \
|
||||
(AR5K_INIT_USEC_TURBO) \
|
||||
)
|
||||
#define AR5K_INIT_PROTO_TIME_CNTRL ( \
|
||||
(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \
|
||||
(AR5K_INIT_PROG_IFS) \
|
||||
)
|
||||
#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \
|
||||
(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
|
||||
(AR5K_INIT_PROG_IFS_TURBO) \
|
||||
)
|
||||
#define AR5K_INIT_BEACON_CONTROL ( \
|
||||
(AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \
|
||||
(AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \
|
||||
)
|
||||
|
||||
/*
|
||||
* Non-common initial register values which have to be loaded into the
|
||||
* card at boot time and after each reset.
|
||||
*/
|
||||
|
||||
/* Register dumps are done per operation mode */
|
||||
#define AR5K_INI_RFGAIN_5GHZ 0
|
||||
#define AR5K_INI_RFGAIN_2GHZ 1
|
||||
|
||||
#define AR5K_INI_VAL_11A 0
|
||||
#define AR5K_INI_VAL_11A_TURBO 1
|
||||
#define AR5K_INI_VAL_11B 2
|
||||
#define AR5K_INI_VAL_11G 3
|
||||
#define AR5K_INI_VAL_11G_TURBO 4
|
||||
#define AR5K_INI_VAL_XR 0
|
||||
#define AR5K_INI_VAL_MAX 5
|
||||
|
||||
#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS
|
||||
|
||||
static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
|
||||
{
|
||||
u32 retval = 0, bit, i;
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
bit = (val >> i) & 1;
|
||||
retval = (retval << 1) | bit;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************\
|
||||
* DMA and interrupt masking functions *
|
||||
\*************************************/
|
||||
|
||||
/*
|
||||
* dma.c - DMA and interrupt masking functions
|
||||
*
|
||||
* Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
|
||||
* handle queue setup for 5210 chipset (rest are handled on qcu.c).
|
||||
* Also we setup interrupt mask register (IMR) and read the various iterrupt
|
||||
* status registers (ISR).
|
||||
*
|
||||
* TODO: Handle SISR on 5211+ and introduce a function to return the queue
|
||||
* number that resulted the interrupt.
|
||||
*/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*********\
|
||||
* Receive *
|
||||
\*********/
|
||||
|
||||
/**
|
||||
* ath5k_hw_start_rx_dma - Start DMA receive
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
|
||||
ath5k_hw_reg_read(ah, AR5K_CR);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_stop_rx_dma - Stop DMA receive
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*/
|
||||
int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
|
||||
|
||||
/*
|
||||
* It may take some time to disable the DMA receive unit
|
||||
*/
|
||||
for (i = 2000; i > 0 &&
|
||||
(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
|
||||
i--)
|
||||
udelay(10);
|
||||
|
||||
return i ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_rxdp - Get RX Descriptor's address
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*
|
||||
* XXX: Is RXDP read and clear ?
|
||||
*/
|
||||
u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
|
||||
{
|
||||
return ath5k_hw_reg_read(ah, AR5K_RXDP);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_rxdp - Set RX Descriptor's address
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @phys_addr: RX descriptor address
|
||||
*
|
||||
* XXX: Should we check if rx is enabled before setting rxdp ?
|
||||
*/
|
||||
void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
|
||||
}
|
||||
|
||||
|
||||
/**********\
|
||||
* Transmit *
|
||||
\**********/
|
||||
|
||||
/**
|
||||
* ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @queue: The hw queue number
|
||||
*
|
||||
* Start DMA transmit for a specific queue and since 5210 doesn't have
|
||||
* QCU/DCU, set up queue parameters for 5210 here based on queue type (one
|
||||
* queue for normal data and one queue for beacons). For queue setup
|
||||
* on newer chips check out qcu.c. Returns -EINVAL if queue number is out
|
||||
* of range or if queue is already disabled.
|
||||
*
|
||||
* NOTE: Must be called after setting up tx control descriptor for that
|
||||
* queue (see below).
|
||||
*/
|
||||
int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
u32 tx_queue;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
/* Return if queue is declared inactive */
|
||||
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return -EIO;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
|
||||
|
||||
/*
|
||||
* Set the queue by type on 5210
|
||||
*/
|
||||
switch (ah->ah_txq[queue].tqi_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
|
||||
ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
|
||||
AR5K_BSR);
|
||||
break;
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
|
||||
ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
|
||||
AR5K_BCR_BDMAE, AR5K_BSR);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Start queue */
|
||||
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
|
||||
ath5k_hw_reg_read(ah, AR5K_CR);
|
||||
} else {
|
||||
/* Return if queue is disabled */
|
||||
if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
|
||||
return -EIO;
|
||||
|
||||
/* Start queue */
|
||||
AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @queue: The hw queue number
|
||||
*
|
||||
* Stop DMA transmit on a specific hw queue and drain queue so we don't
|
||||
* have any pending frames. Returns -EBUSY if we still have pending frames,
|
||||
* -EINVAL if queue number is out of range.
|
||||
*
|
||||
* TODO: Test queue drain code
|
||||
*/
|
||||
int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
unsigned int i = 100;
|
||||
u32 tx_queue, pending;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
/* Return if queue is declared inactive */
|
||||
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return -EIO;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
|
||||
|
||||
/*
|
||||
* Set by queue type
|
||||
*/
|
||||
switch (ah->ah_txq[queue].tqi_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
/* XXX Fix me... */
|
||||
tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_BSR);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Stop queue */
|
||||
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
|
||||
ath5k_hw_reg_read(ah, AR5K_CR);
|
||||
} else {
|
||||
/*
|
||||
* Schedule TX disable and wait until queue is empty
|
||||
*/
|
||||
AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
|
||||
|
||||
/*Check for pending frames*/
|
||||
do {
|
||||
pending = ath5k_hw_reg_read(ah,
|
||||
AR5K_QUEUE_STATUS(queue)) &
|
||||
AR5K_QCU_STS_FRMPENDCNT;
|
||||
udelay(100);
|
||||
} while (--i && pending);
|
||||
|
||||
/* Clear register */
|
||||
ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
|
||||
if (pending)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* TODO: Check for success else return error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @queue: The hw queue number
|
||||
*
|
||||
* Get TX descriptor's address for a specific queue. For 5210 we ignore
|
||||
* the queue number and use tx queue type since we only have 2 queues.
|
||||
* We use TXDP0 for normal data queue and TXDP1 for beacon queue.
|
||||
* For newer chips with QCU/DCU we just read the corresponding TXDP register.
|
||||
*
|
||||
* XXX: Is TXDP read and clear ?
|
||||
*/
|
||||
u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
u16 tx_reg;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
/*
|
||||
* Get the transmit queue descriptor pointer from the selected queue
|
||||
*/
|
||||
/*5210 doesn't have QCU*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
switch (ah->ah_txq[queue].tqi_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
tx_reg = AR5K_NOQCU_TXDP0;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
tx_reg = AR5K_NOQCU_TXDP1;
|
||||
break;
|
||||
default:
|
||||
return 0xffffffff;
|
||||
}
|
||||
} else {
|
||||
tx_reg = AR5K_QUEUE_TXDP(queue);
|
||||
}
|
||||
|
||||
return ath5k_hw_reg_read(ah, tx_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @queue: The hw queue number
|
||||
*
|
||||
* Set TX descriptor's address for a specific queue. For 5210 we ignore
|
||||
* the queue number and we use tx queue type since we only have 2 queues
|
||||
* so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
|
||||
* For newer chips with QCU/DCU we just set the corresponding TXDP register.
|
||||
* Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
|
||||
* active.
|
||||
*/
|
||||
int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
|
||||
{
|
||||
u16 tx_reg;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
/*
|
||||
* Set the transmit queue descriptor pointer register by type
|
||||
* on 5210
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
switch (ah->ah_txq[queue].tqi_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
tx_reg = AR5K_NOQCU_TXDP0;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
tx_reg = AR5K_NOQCU_TXDP1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Set the transmit queue descriptor pointer for
|
||||
* the selected queue on QCU for 5211+
|
||||
* (this won't work if the queue is still active)
|
||||
*/
|
||||
if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
|
||||
return -EIO;
|
||||
|
||||
tx_reg = AR5K_QUEUE_TXDP(queue);
|
||||
}
|
||||
|
||||
/* Set descriptor pointer */
|
||||
ath5k_hw_reg_write(ah, phys_addr, tx_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_update_tx_triglevel - Update tx trigger level
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @increase: Flag to force increase of trigger level
|
||||
*
|
||||
* This function increases/decreases the tx trigger level for the tx fifo
|
||||
* buffer (aka FIFO threshold) that is used to indicate when PCU flushes
|
||||
* the buffer and transmits it's data. Lowering this results sending small
|
||||
* frames more quickly but can lead to tx underruns, raising it a lot can
|
||||
* result other problems (i think bmiss is related). Right now we start with
|
||||
* the lowest possible (64Bytes) and if we get tx underrun we increase it using
|
||||
* the increase flag. Returns -EIO if we have have reached maximum/minimum.
|
||||
*
|
||||
* XXX: Link this with tx DMA size ?
|
||||
* XXX: Use it to save interrupts ?
|
||||
* TODO: Needs testing, i think it's related to bmiss...
|
||||
*/
|
||||
int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
|
||||
{
|
||||
u32 trigger_level, imr;
|
||||
int ret = -EIO;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/*
|
||||
* Disable interrupts by setting the mask
|
||||
*/
|
||||
imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
|
||||
|
||||
trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
|
||||
AR5K_TXCFG_TXFULL);
|
||||
|
||||
if (!increase) {
|
||||
if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
|
||||
goto done;
|
||||
} else
|
||||
trigger_level +=
|
||||
((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
|
||||
|
||||
/*
|
||||
* Update trigger level on success
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
|
||||
else
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
|
||||
AR5K_TXCFG_TXFULL, trigger_level);
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
/*
|
||||
* Restore interrupt mask
|
||||
*/
|
||||
ath5k_hw_set_imr(ah, imr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************\
|
||||
* Interrupt masking *
|
||||
\*******************/
|
||||
|
||||
/**
|
||||
* ath5k_hw_is_intr_pending - Check if we have pending interrupts
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
*
|
||||
* Check if we have pending interrupts to process. Returns 1 if we
|
||||
* have pending interrupts and 0 if we haven't.
|
||||
*/
|
||||
bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
return ath5k_hw_reg_read(ah, AR5K_INTPEND);
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_get_isr - Get interrupt status
|
||||
*
|
||||
* @ah: The @struct ath5k_hw
|
||||
* @interrupt_mask: Driver's interrupt mask used to filter out
|
||||
* interrupts in sw.
|
||||
*
|
||||
* This function is used inside our interrupt handler to determine the reason
|
||||
* for the interrupt by reading Primary Interrupt Status Register. Returns an
|
||||
* abstract interrupt status mask which is mostly ISR with some uncommon bits
|
||||
* being mapped on some standard non hw-specific positions
|
||||
* (check out &ath5k_int).
|
||||
*
|
||||
* NOTE: We use read-and-clear register, so after this function is called ISR
|
||||
* is zeroed.
|
||||
*
|
||||
* XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all
|
||||
* plus it can be misleading (one might thing that we save interrupts this way)
|
||||
*/
|
||||
int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/*
|
||||
* Read interrupt status from the Interrupt Status register
|
||||
* on 5210
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
data = ath5k_hw_reg_read(ah, AR5K_ISR);
|
||||
if (unlikely(data == AR5K_INT_NOCARD)) {
|
||||
*interrupt_mask = data;
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Read interrupt status from the Read-And-Clear
|
||||
* shadow register.
|
||||
* Note: PISR/SISR Not available on 5210
|
||||
*/
|
||||
data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get abstract interrupt mask (driver-compatible)
|
||||
*/
|
||||
*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
|
||||
|
||||
if (unlikely(data == AR5K_INT_NOCARD))
|
||||
return -ENODEV;
|
||||
|
||||
if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
|
||||
*interrupt_mask |= AR5K_INT_RX;
|
||||
|
||||
if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
|
||||
| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
|
||||
*interrupt_mask |= AR5K_INT_TX;
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
/*HIU = Host Interface Unit (PCI etc)*/
|
||||
if (unlikely(data & (AR5K_ISR_HIUERR)))
|
||||
*interrupt_mask |= AR5K_INT_FATAL;
|
||||
|
||||
/*Beacon Not Ready*/
|
||||
if (unlikely(data & (AR5K_ISR_BNR)))
|
||||
*interrupt_mask |= AR5K_INT_BNR;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: BMISS interrupts may occur after association.
|
||||
* I found this on 5210 code but it needs testing. If this is
|
||||
* true we should disable them before assoc and re-enable them
|
||||
* after a successfull assoc + some jiffies.
|
||||
*/
|
||||
#if 0
|
||||
interrupt_mask &= ~AR5K_INT_BMISS;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In case we didn't handle anything,
|
||||
* print the register value.
|
||||
*/
|
||||
if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
|
||||
ATH5K_PRINTF("0x%08x\n", data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ath5k_hw_set_imr - Set interrupt mask
|
||||
*
|
||||
* @ah: The &struct ath5k_hw
|
||||
* @new_mask: The new interrupt mask to be set
|
||||
*
|
||||
* Set the interrupt mask in hw to save interrupts. We do that by mapping
|
||||
* ath5k_int bits to hw-specific bits to remove abstraction and writing
|
||||
* Interrupt Mask Register.
|
||||
*/
|
||||
enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
|
||||
{
|
||||
enum ath5k_int old_mask, int_mask;
|
||||
|
||||
/*
|
||||
* Disable card interrupts to prevent any race conditions
|
||||
* (they will be re-enabled afterwards).
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
|
||||
ath5k_hw_reg_read(ah, AR5K_IER);
|
||||
|
||||
old_mask = ah->ah_imr;
|
||||
|
||||
/*
|
||||
* Add additional, chipset-dependent interrupt mask flags
|
||||
* and write them to the IMR (interrupt mask register).
|
||||
*/
|
||||
int_mask = new_mask & AR5K_INT_COMMON;
|
||||
|
||||
if (new_mask & AR5K_INT_RX)
|
||||
int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
|
||||
AR5K_IMR_RXDESC;
|
||||
|
||||
if (new_mask & AR5K_INT_TX)
|
||||
int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
|
||||
AR5K_IMR_TXURN;
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
if (new_mask & AR5K_INT_FATAL) {
|
||||
int_mask |= AR5K_IMR_HIUERR;
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
|
||||
AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
|
||||
}
|
||||
}
|
||||
|
||||
ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
|
||||
|
||||
/* Store new interrupt mask */
|
||||
ah->ah_imr = new_mask;
|
||||
|
||||
/* ..re-enable interrupts */
|
||||
ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
|
||||
ath5k_hw_reg_read(ah, AR5K_IER);
|
||||
|
||||
return old_mask;
|
||||
}
|
||||
|
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*************************************\
|
||||
* EEPROM access functions and helpers *
|
||||
\*************************************/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Read from eeprom
|
||||
*/
|
||||
static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
|
||||
{
|
||||
u32 status, timeout;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
/*
|
||||
* Initialize EEPROM access
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
|
||||
(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
|
||||
} else {
|
||||
ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
|
||||
AR5K_EEPROM_CMD_READ);
|
||||
}
|
||||
|
||||
for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
|
||||
status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
|
||||
if (status & AR5K_EEPROM_STAT_RDDONE) {
|
||||
if (status & AR5K_EEPROM_STAT_RDERR)
|
||||
return -EIO;
|
||||
*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
|
||||
0xffff);
|
||||
return 0;
|
||||
}
|
||||
udelay(15);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate binary channel representation in EEPROM to frequency
|
||||
*/
|
||||
static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
|
||||
unsigned int mode)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
if (bin == AR5K_EEPROM_CHANNEL_DIS)
|
||||
return bin;
|
||||
|
||||
if (mode == AR5K_EEPROM_MODE_11A) {
|
||||
if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
|
||||
val = (5 * bin) + 4800;
|
||||
else
|
||||
val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
|
||||
(bin * 10) + 5100;
|
||||
} else {
|
||||
if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
|
||||
val = bin + 2300;
|
||||
else
|
||||
val = bin + 2400;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read antenna infos from eeprom
|
||||
*/
|
||||
static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
u32 o = *offset;
|
||||
u16 val;
|
||||
int ret, i = 0;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
|
||||
ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
|
||||
ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
|
||||
ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
|
||||
ee->ee_ant_control[mode][i++] = val & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f;
|
||||
ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f;
|
||||
ee->ee_ant_control[mode][i] = (val << 2) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3;
|
||||
ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f;
|
||||
ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f;
|
||||
ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
|
||||
ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
|
||||
ee->ee_ant_control[mode][i++] = val & 0x3f;
|
||||
|
||||
/* Get antenna modes */
|
||||
ah->ah_antenna[mode][0] =
|
||||
(ee->ee_ant_control[mode][0] << 4) | 0x1;
|
||||
ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
|
||||
ee->ee_ant_control[mode][1] |
|
||||
(ee->ee_ant_control[mode][2] << 6) |
|
||||
(ee->ee_ant_control[mode][3] << 12) |
|
||||
(ee->ee_ant_control[mode][4] << 18) |
|
||||
(ee->ee_ant_control[mode][5] << 24);
|
||||
ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
|
||||
ee->ee_ant_control[mode][6] |
|
||||
(ee->ee_ant_control[mode][7] << 6) |
|
||||
(ee->ee_ant_control[mode][8] << 12) |
|
||||
(ee->ee_ant_control[mode][9] << 18) |
|
||||
(ee->ee_ant_control[mode][10] << 24);
|
||||
|
||||
/* return new offset */
|
||||
*offset = o;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read supported modes from eeprom
|
||||
*/
|
||||
static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
u32 o = *offset;
|
||||
u16 val;
|
||||
int ret;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
|
||||
ee->ee_thr_62[mode] = val & 0xff;
|
||||
|
||||
if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
|
||||
ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
|
||||
ee->ee_tx_frm2xpa_enable[mode] = val & 0xff;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff;
|
||||
|
||||
if ((val & 0xff) & 0x80)
|
||||
ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
|
||||
else
|
||||
ee->ee_noise_floor_thr[mode] = val & 0xff;
|
||||
|
||||
if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
|
||||
ee->ee_noise_floor_thr[mode] =
|
||||
mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_xlna_gain[mode] = (val >> 5) & 0xff;
|
||||
ee->ee_x_gain[mode] = (val >> 1) & 0xf;
|
||||
ee->ee_xpd[mode] = val & 0x1;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
|
||||
ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
|
||||
|
||||
if (mode == AR5K_EEPROM_MODE_11A)
|
||||
ee->ee_xr_power[mode] = val & 0x3f;
|
||||
else {
|
||||
ee->ee_ob[mode][0] = val & 0x7;
|
||||
ee->ee_db[mode][0] = (val >> 3) & 0x7;
|
||||
}
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
|
||||
ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
|
||||
ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
|
||||
} else {
|
||||
ee->ee_i_gain[mode] = (val >> 13) & 0x7;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
ee->ee_i_gain[mode] |= (val << 3) & 0x38;
|
||||
|
||||
if (mode == AR5K_EEPROM_MODE_11G)
|
||||
ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
|
||||
mode == AR5K_EEPROM_MODE_11A) {
|
||||
ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
|
||||
ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
|
||||
mode == AR5K_EEPROM_MODE_11G)
|
||||
ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
|
||||
|
||||
/* return new offset */
|
||||
*offset = o;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize eeprom & capabilities structs
|
||||
*/
|
||||
int ath5k_eeprom_init(struct ath5k_hw *ah)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
unsigned int mode, i;
|
||||
int ret;
|
||||
u32 offset;
|
||||
u16 val;
|
||||
|
||||
/* Initial TX thermal adjustment values */
|
||||
ee->ee_tx_clip = 4;
|
||||
ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
|
||||
ee->ee_gain_select = 1;
|
||||
|
||||
/*
|
||||
* Read values from EEPROM and store them in the capability structure
|
||||
*/
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
|
||||
|
||||
/* Return if we have an old EEPROM */
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
|
||||
return 0;
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Validate the checksum of the EEPROM date. There are some
|
||||
* devices with invalid EEPROMs.
|
||||
*/
|
||||
for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
|
||||
cksum ^= val;
|
||||
}
|
||||
if (cksum != AR5K_EEPROM_INFO_CKSUM) {
|
||||
ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
|
||||
ee_ant_gain);
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
|
||||
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
|
||||
ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
|
||||
ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
|
||||
|
||||
AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
|
||||
ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
|
||||
ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get conformance test limit values
|
||||
*/
|
||||
offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
|
||||
ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
|
||||
|
||||
for (i = 0; i < ee->ee_ctls; i++) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_ctl[i] = (val >> 8) & 0xff;
|
||||
ee->ee_ctl[i + 1] = val & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get values for 802.11a (5GHz)
|
||||
*/
|
||||
mode = AR5K_EEPROM_MODE_11A;
|
||||
|
||||
ee->ee_turbo_max_power[mode] =
|
||||
AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
|
||||
|
||||
offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
|
||||
|
||||
ret = ath5k_eeprom_read_ants(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
|
||||
ee->ee_ob[mode][3] = (val >> 5) & 0x7;
|
||||
ee->ee_db[mode][3] = (val >> 2) & 0x7;
|
||||
ee->ee_ob[mode][2] = (val << 1) & 0x7;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
|
||||
ee->ee_db[mode][2] = (val >> 12) & 0x7;
|
||||
ee->ee_ob[mode][1] = (val >> 9) & 0x7;
|
||||
ee->ee_db[mode][1] = (val >> 6) & 0x7;
|
||||
ee->ee_ob[mode][0] = (val >> 3) & 0x7;
|
||||
ee->ee_db[mode][0] = val & 0x7;
|
||||
|
||||
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_margin_tx_rx[mode] = val & 0x3f;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get values for 802.11b (2.4GHz)
|
||||
*/
|
||||
mode = AR5K_EEPROM_MODE_11B;
|
||||
offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
|
||||
|
||||
ret = ath5k_eeprom_read_ants(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
|
||||
ee->ee_ob[mode][1] = (val >> 4) & 0x7;
|
||||
ee->ee_db[mode][1] = val & 0x7;
|
||||
|
||||
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_cal_pier[mode][0] =
|
||||
ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
|
||||
ee->ee_cal_pier[mode][1] =
|
||||
ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_cal_pier[mode][2] =
|
||||
ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
|
||||
}
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
|
||||
ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
|
||||
|
||||
/*
|
||||
* Get values for 802.11g (2.4GHz)
|
||||
*/
|
||||
mode = AR5K_EEPROM_MODE_11G;
|
||||
offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
|
||||
|
||||
ret = ath5k_eeprom_read_ants(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
|
||||
ee->ee_ob[mode][1] = (val >> 4) & 0x7;
|
||||
ee->ee_db[mode][1] = val & 0x7;
|
||||
|
||||
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_cal_pier[mode][0] =
|
||||
ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
|
||||
ee->ee_cal_pier[mode][1] =
|
||||
ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_turbo_max_power[mode] = val & 0x7f;
|
||||
ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_cal_pier[mode][2] =
|
||||
ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
|
||||
ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
|
||||
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
|
||||
ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
|
||||
AR5K_EEPROM_READ(offset++, val);
|
||||
ee->ee_cck_ofdm_gain_delta = val & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 5GHz EEPROM channels
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the MAC address from eeprom
|
||||
*/
|
||||
int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
|
||||
{
|
||||
u8 mac_d[ETH_ALEN];
|
||||
u32 total, offset;
|
||||
u16 data;
|
||||
int octet, ret;
|
||||
|
||||
memset(mac, 0, ETH_ALEN);
|
||||
memset(mac_d, 0, ETH_ALEN);
|
||||
|
||||
ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
|
||||
ret = ath5k_hw_eeprom_read(ah, offset, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
total += data;
|
||||
mac_d[octet + 1] = data & 0xff;
|
||||
mac_d[octet] = data >> 8;
|
||||
octet += 2;
|
||||
}
|
||||
|
||||
memcpy(mac, mac_d, ETH_ALEN);
|
||||
|
||||
if (!total || total == 3 * 0xffff)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
|
||||
*/
|
||||
#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */
|
||||
#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */
|
||||
#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */
|
||||
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
|
||||
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
|
||||
|
||||
#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
|
||||
#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
|
||||
#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
|
||||
#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
|
||||
#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
|
||||
#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
|
||||
#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
|
||||
#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
|
||||
#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
|
||||
#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
|
||||
#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
|
||||
#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
|
||||
#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
|
||||
#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
|
||||
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
|
||||
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
|
||||
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
|
||||
#define AR5K_EEPROM_INFO_CKSUM 0xffff
|
||||
#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
|
||||
|
||||
#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */
|
||||
#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */
|
||||
#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */
|
||||
#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */
|
||||
#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
|
||||
#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
|
||||
#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_3 0x4003
|
||||
#define AR5K_EEPROM_VERSION_4_4 0x4004
|
||||
#define AR5K_EEPROM_VERSION_4_5 0x4005
|
||||
#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
|
||||
#define AR5K_EEPROM_VERSION_4_7 0x4007
|
||||
|
||||
#define AR5K_EEPROM_MODE_11A 0
|
||||
#define AR5K_EEPROM_MODE_11B 1
|
||||
#define AR5K_EEPROM_MODE_11G 2
|
||||
|
||||
#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
|
||||
#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */
|
||||
#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
|
||||
#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
|
||||
#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */
|
||||
#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
|
||||
|
||||
#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c
|
||||
#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
|
||||
#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002
|
||||
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
|
||||
|
||||
/* Newer EEPROMs are using a different offset */
|
||||
#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
|
||||
(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
|
||||
|
||||
#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
|
||||
#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
|
||||
#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
|
||||
|
||||
/* calibration settings */
|
||||
#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
|
||||
#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
|
||||
#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
|
||||
#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */
|
||||
|
||||
/* [3.1 - 3.3] */
|
||||
#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec
|
||||
#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed
|
||||
|
||||
/* Misc values available since EEPROM 4.0 */
|
||||
#define AR5K_EEPROM_MISC0 0x00c4
|
||||
#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
|
||||
#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
|
||||
#define AR5K_EEPROM_MISC1 0x00c5
|
||||
#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
|
||||
#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
|
||||
|
||||
|
||||
/* Some EEPROM defines */
|
||||
#define AR5K_EEPROM_EEP_SCALE 100
|
||||
#define AR5K_EEPROM_EEP_DELTA 10
|
||||
#define AR5K_EEPROM_N_MODES 3
|
||||
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
||||
#define AR5K_EEPROM_MAX_CHAN 10
|
||||
#define AR5K_EEPROM_N_PCDAC 11
|
||||
#define AR5K_EEPROM_N_TEST_FREQ 8
|
||||
#define AR5K_EEPROM_N_EDGES 8
|
||||
#define AR5K_EEPROM_N_INTERCEPTS 11
|
||||
#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
|
||||
#define AR5K_EEPROM_PCDAC_M 0x3f
|
||||
#define AR5K_EEPROM_PCDAC_START 1
|
||||
#define AR5K_EEPROM_PCDAC_STOP 63
|
||||
#define AR5K_EEPROM_PCDAC_STEP 1
|
||||
#define AR5K_EEPROM_NON_EDGE_M 0x40
|
||||
#define AR5K_EEPROM_CHANNEL_POWER 8
|
||||
#define AR5K_EEPROM_N_OBDB 4
|
||||
#define AR5K_EEPROM_OBDB_DIS 0xffff
|
||||
#define AR5K_EEPROM_CHANNEL_DIS 0xff
|
||||
#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10)
|
||||
#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32)
|
||||
#define AR5K_EEPROM_MAX_CTLS 32
|
||||
#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4
|
||||
#define AR5K_EEPROM_N_XPD0_POINTS 4
|
||||
#define AR5K_EEPROM_N_XPD3_POINTS 3
|
||||
#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35
|
||||
#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55
|
||||
#define AR5K_EEPROM_POWER_M 0x3f
|
||||
#define AR5K_EEPROM_POWER_MIN 0
|
||||
#define AR5K_EEPROM_POWER_MAX 3150
|
||||
#define AR5K_EEPROM_POWER_STEP 50
|
||||
#define AR5K_EEPROM_POWER_TABLE_SIZE 64
|
||||
#define AR5K_EEPROM_N_POWER_LOC_11B 4
|
||||
#define AR5K_EEPROM_N_POWER_LOC_11G 6
|
||||
#define AR5K_EEPROM_I_GAIN 10
|
||||
#define AR5K_EEPROM_CCK_OFDM_DELTA 15
|
||||
#define AR5K_EEPROM_N_IQ_CAL 2
|
||||
|
||||
#define AR5K_EEPROM_READ(_o, _v) do { \
|
||||
ret = ath5k_hw_eeprom_read(ah, (_o), &(_v)); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
} while (0)
|
||||
|
||||
#define AR5K_EEPROM_READ_HDR(_o, _v) \
|
||||
AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \
|
||||
|
||||
/* Struct to hold EEPROM calibration data */
|
||||
struct ath5k_eeprom_info {
|
||||
u16 ee_magic;
|
||||
u16 ee_protect;
|
||||
u16 ee_regdomain;
|
||||
u16 ee_version;
|
||||
u16 ee_header;
|
||||
u16 ee_ant_gain;
|
||||
u16 ee_misc0;
|
||||
u16 ee_misc1;
|
||||
u16 ee_cck_ofdm_gain_delta;
|
||||
u16 ee_cck_ofdm_power_delta;
|
||||
u16 ee_scaled_cck_delta;
|
||||
|
||||
/* Used for tx thermal adjustment (eeprom_init, rfregs) */
|
||||
u16 ee_tx_clip;
|
||||
u16 ee_pwd_84;
|
||||
u16 ee_pwd_90;
|
||||
u16 ee_gain_select;
|
||||
|
||||
/* RF Calibration settings (reset, rfregs) */
|
||||
u16 ee_i_cal[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_q_cal[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_fixed_bias[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xr_power[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_switch_settling[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
|
||||
u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
|
||||
u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
|
||||
u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_thr_62[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xlna_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_xpd[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_x_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_i_gain[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
|
||||
|
||||
/* Unused */
|
||||
u16 ee_false_detect[AR5K_EEPROM_N_MODES];
|
||||
u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
|
||||
u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
|
||||
|
||||
/* Conformance test limits (Unused) */
|
||||
u16 ee_ctls;
|
||||
u16 ee_ctl[AR5K_EEPROM_MAX_CTLS];
|
||||
|
||||
/* Noise Floor Calibration settings */
|
||||
s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
|
||||
s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES];
|
||||
s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES];
|
||||
};
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/****************\
|
||||
GPIO Functions
|
||||
\****************/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Set led state
|
||||
*/
|
||||
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
|
||||
{
|
||||
u32 led;
|
||||
/*5210 has different led mode handling*/
|
||||
u32 led_5210;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/*Reset led status*/
|
||||
if (ah->ah_version != AR5K_AR5210)
|
||||
AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
|
||||
AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED);
|
||||
else
|
||||
AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
|
||||
|
||||
/*
|
||||
* Some blinking values, define at your wish
|
||||
*/
|
||||
switch (state) {
|
||||
case AR5K_LED_SCAN:
|
||||
case AR5K_LED_AUTH:
|
||||
led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
|
||||
led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
|
||||
break;
|
||||
|
||||
case AR5K_LED_INIT:
|
||||
led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
|
||||
led_5210 = AR5K_PCICFG_LED_PEND;
|
||||
break;
|
||||
|
||||
case AR5K_LED_ASSOC:
|
||||
case AR5K_LED_RUN:
|
||||
led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
|
||||
led_5210 = AR5K_PCICFG_LED_ASSOC;
|
||||
break;
|
||||
|
||||
default:
|
||||
led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
|
||||
led_5210 = AR5K_PCICFG_LED_PEND;
|
||||
break;
|
||||
}
|
||||
|
||||
/*Write new status to the register*/
|
||||
if (ah->ah_version != AR5K_AR5210)
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
|
||||
else
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set GPIO inputs
|
||||
*/
|
||||
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
|
||||
| AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set GPIO outputs
|
||||
*/
|
||||
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
|
||||
| AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get GPIO state
|
||||
*/
|
||||
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
return 0xffffffff;
|
||||
|
||||
/* GPIO input magic */
|
||||
return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
|
||||
0x1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set GPIO state
|
||||
*/
|
||||
int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
|
||||
{
|
||||
u32 data;
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
/* GPIO output magic */
|
||||
data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
|
||||
|
||||
data &= ~(1 << gpio);
|
||||
data |= (val & 1) << gpio;
|
||||
|
||||
ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the GPIO interrupt (RFKill switch)
|
||||
*/
|
||||
void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
|
||||
u32 interrupt_level)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (gpio > AR5K_NUM_GPIO)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Set the GPIO interrupt
|
||||
*/
|
||||
data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
|
||||
~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
|
||||
AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
|
||||
(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
|
||||
|
||||
ath5k_hw_reg_write(ah, interrupt_level ? data :
|
||||
(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
|
||||
|
||||
ah->ah_imr |= AR5K_IMR_GPIO;
|
||||
|
||||
/* Enable GPIO interrupts */
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Initial register settings functions
|
||||
*
|
||||
* Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
|
||||
* Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -20,13 +20,9 @@
|
|||
*/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "base.h"
|
||||
#include "reg.h"
|
||||
|
||||
/*
|
||||
* MAC/PHY REGISTERS
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Mode-independent initial register writes
|
||||
|
@ -65,10 +61,10 @@ static const struct ath5k_ini ar5210_ini[] = {
|
|||
{ AR5K_TXCFG, AR5K_DMASIZE_128B },
|
||||
{ AR5K_RXCFG, AR5K_DMASIZE_128B },
|
||||
{ AR5K_CFG, AR5K_INIT_CFG },
|
||||
{ AR5K_TOPS, AR5K_INIT_TOPS },
|
||||
{ AR5K_RXNOFRM, AR5K_INIT_RXNOFRM },
|
||||
{ AR5K_RPGTO, AR5K_INIT_RPGTO },
|
||||
{ AR5K_TXNOFRM, AR5K_INIT_TXNOFRM },
|
||||
{ AR5K_TOPS, 8 },
|
||||
{ AR5K_RXNOFRM, 8 },
|
||||
{ AR5K_RPGTO, 0 },
|
||||
{ AR5K_TXNOFRM, 0 },
|
||||
{ AR5K_SFR, 0 },
|
||||
{ AR5K_MIBC, 0 },
|
||||
{ AR5K_MISC, 0 },
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* PHY functions
|
||||
*
|
||||
* Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
|
||||
* Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -19,6 +19,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define _ATH5K_PHY
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ath5k.h"
|
||||
|
@ -2501,3 +2503,5 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power)
|
|||
|
||||
return ath5k_hw_txpower(ah, channel, power);
|
||||
}
|
||||
|
||||
#undef _ATH5K_PHY
|
||||
|
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
/********************************************\
|
||||
Queue Control Unit, DFS Control Unit Functions
|
||||
\********************************************/
|
||||
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "debug.h"
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Get properties for a transmit queue
|
||||
*/
|
||||
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
struct ath5k_txq_info *queue_info)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set properties for a transmit queue
|
||||
*/
|
||||
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
|
||||
const struct ath5k_txq_info *queue_info)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return -EIO;
|
||||
|
||||
memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
|
||||
|
||||
/*XXX: Is this supported on 5210 ?*/
|
||||
if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
|
||||
((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
|
||||
(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
|
||||
queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
|
||||
ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a transmit queue
|
||||
*/
|
||||
int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
|
||||
struct ath5k_txq_info *queue_info)
|
||||
{
|
||||
unsigned int queue;
|
||||
int ret;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/*
|
||||
* Get queue by type
|
||||
*/
|
||||
/*5210 only has 2 queues*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
switch (queue_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (queue_type) {
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
|
||||
ah->ah_txq[queue].tqi_type !=
|
||||
AR5K_TX_QUEUE_INACTIVE; queue++) {
|
||||
|
||||
if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AR5K_TX_QUEUE_UAPSD:
|
||||
queue = AR5K_TX_QUEUE_ID_UAPSD;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
queue = AR5K_TX_QUEUE_ID_BEACON;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
queue = AR5K_TX_QUEUE_ID_CAB;
|
||||
break;
|
||||
case AR5K_TX_QUEUE_XR_DATA:
|
||||
if (ah->ah_version != AR5K_AR5212)
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"XR data queues only supported in"
|
||||
" 5212!\n");
|
||||
queue = AR5K_TX_QUEUE_ID_XR_DATA;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup internal queue structure
|
||||
*/
|
||||
memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
|
||||
ah->ah_txq[queue].tqi_type = queue_type;
|
||||
|
||||
if (queue_info != NULL) {
|
||||
queue_info->tqi_type = queue_type;
|
||||
ret = ath5k_hw_set_tx_queueprops(ah, queue, queue_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use ah_txq_status to hold a temp value for
|
||||
* the Secondary interrupt mask registers on 5211+
|
||||
* check out ath5k_hw_reset_tx_queue
|
||||
*/
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get number of pending frames
|
||||
* for a specific queue [5211+]
|
||||
*/
|
||||
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
/* Return if queue is declared inactive */
|
||||
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return false;
|
||||
|
||||
/* XXX: How about AR5K_CFG_TXCNT ? */
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
return false;
|
||||
|
||||
return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a transmit queue inactive
|
||||
*/
|
||||
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
|
||||
return;
|
||||
|
||||
/* This queue will be skipped in further operations */
|
||||
ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
|
||||
/*For SIMR setup*/
|
||||
AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set DFS properties for a transmit queue on DCU
|
||||
*/
|
||||
int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
||||
{
|
||||
u32 cw_min, cw_max, retry_lg, retry_sh;
|
||||
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
tq = &ah->ah_txq[queue];
|
||||
|
||||
if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
|
||||
return 0;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
/* Only handle data queues, others will be ignored */
|
||||
if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
|
||||
return 0;
|
||||
|
||||
/* Set Slot time */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
|
||||
AR5K_SLOT_TIME);
|
||||
/* Set ACK_CTS timeout */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
|
||||
AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
|
||||
/* Set Transmit Latency */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
AR5K_INIT_TRANSMIT_LATENCY_TURBO :
|
||||
AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
|
||||
|
||||
/* Set IFS0 */
|
||||
if (ah->ah_turbo) {
|
||||
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
|
||||
(ah->ah_aifs + tq->tqi_aifs) *
|
||||
AR5K_INIT_SLOT_TIME_TURBO) <<
|
||||
AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
|
||||
AR5K_IFS0);
|
||||
} else {
|
||||
ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
|
||||
(ah->ah_aifs + tq->tqi_aifs) *
|
||||
AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
|
||||
AR5K_INIT_SIFS, AR5K_IFS0);
|
||||
}
|
||||
|
||||
/* Set IFS1 */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
|
||||
AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
|
||||
/* Set AR5K_PHY_SETTLING */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
|
||||
| 0x38 :
|
||||
(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
|
||||
| 0x1C,
|
||||
AR5K_PHY_SETTLING);
|
||||
/* Set Frame Control Register */
|
||||
ath5k_hw_reg_write(ah, ah->ah_turbo ?
|
||||
(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
|
||||
AR5K_PHY_TURBO_SHORT | 0x2020) :
|
||||
(AR5K_PHY_FRAME_CTL_INI | 0x1020),
|
||||
AR5K_PHY_FRAME_CTL_5210);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate cwmin/max by channel mode
|
||||
*/
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS;
|
||||
/*XR is only supported on 5212*/
|
||||
if (IS_CHAN_XR(ah->ah_current_channel) &&
|
||||
ah->ah_version == AR5K_AR5212) {
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS_XR;
|
||||
/*B mode is not supported on 5210*/
|
||||
} else if (IS_CHAN_B(ah->ah_current_channel) &&
|
||||
ah->ah_version != AR5K_AR5210) {
|
||||
cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
|
||||
cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
|
||||
ah->ah_aifs = AR5K_TUNE_AIFS_11B;
|
||||
}
|
||||
|
||||
cw_min = 1;
|
||||
while (cw_min < ah->ah_cw_min)
|
||||
cw_min = (cw_min << 1) | 1;
|
||||
|
||||
cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
|
||||
((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
|
||||
cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
|
||||
((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
|
||||
|
||||
/*
|
||||
* Calculate and set retry limits
|
||||
*/
|
||||
if (ah->ah_software_retry) {
|
||||
/* XXX Need to test this */
|
||||
retry_lg = ah->ah_limit_tx_retries;
|
||||
retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
|
||||
AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
|
||||
} else {
|
||||
retry_lg = AR5K_INIT_LG_RETRY;
|
||||
retry_sh = AR5K_INIT_SH_RETRY;
|
||||
}
|
||||
|
||||
/*No QCU/DCU [5210]*/
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
ath5k_hw_reg_write(ah,
|
||||
(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
|
||||
| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
|
||||
AR5K_NODCU_RETRY_LMT_SLG_RETRY)
|
||||
| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
|
||||
AR5K_NODCU_RETRY_LMT_SSH_RETRY)
|
||||
| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
|
||||
| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
|
||||
AR5K_NODCU_RETRY_LMT);
|
||||
} else {
|
||||
/*QCU/DCU [5211+]*/
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
|
||||
AR5K_DCU_RETRY_LMT_SLG_RETRY) |
|
||||
AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
|
||||
AR5K_DCU_RETRY_LMT_SSH_RETRY) |
|
||||
AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
|
||||
AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
|
||||
AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
|
||||
|
||||
/*===Rest is also for QCU/DCU only [5211+]===*/
|
||||
|
||||
/*
|
||||
* Set initial content window (cw_min/cw_max)
|
||||
* and arbitrated interframe space (aifs)...
|
||||
*/
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
|
||||
AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
|
||||
AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
|
||||
AR5K_DCU_LCL_IFS_AIFS),
|
||||
AR5K_QUEUE_DFS_LOCAL_IFS(queue));
|
||||
|
||||
/*
|
||||
* Set misc registers
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
|
||||
AR5K_QUEUE_MISC(queue));
|
||||
|
||||
if (tq->tqi_cbr_period) {
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
|
||||
AR5K_QCU_CBRCFG_INTVAL) |
|
||||
AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
|
||||
AR5K_QCU_CBRCFG_ORN_THRES),
|
||||
AR5K_QUEUE_CBRCFG(queue));
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_FRSHED_CBR);
|
||||
if (tq->tqi_cbr_overflow_limit)
|
||||
AR5K_REG_ENABLE_BITS(ah,
|
||||
AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_CBR_THRES_ENABLE);
|
||||
}
|
||||
|
||||
if (tq->tqi_ready_time)
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
|
||||
AR5K_QCU_RDYTIMECFG_INTVAL) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
AR5K_QUEUE_RDYTIMECFG(queue));
|
||||
|
||||
if (tq->tqi_burst_time) {
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
|
||||
AR5K_DCU_CHAN_TIME_DUR) |
|
||||
AR5K_DCU_CHAN_TIME_ENABLE,
|
||||
AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
|
||||
|
||||
if (tq->tqi_flags
|
||||
& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
|
||||
AR5K_REG_ENABLE_BITS(ah,
|
||||
AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_RDY_VEOL_POLICY);
|
||||
}
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
|
||||
ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
|
||||
AR5K_QUEUE_DFS_MISC(queue));
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
|
||||
ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
|
||||
AR5K_QUEUE_DFS_MISC(queue));
|
||||
|
||||
/*
|
||||
* Set registers by queue type
|
||||
*/
|
||||
switch (tq->tqi_type) {
|
||||
case AR5K_TX_QUEUE_BEACON:
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_FRSHED_DBA_GT |
|
||||
AR5K_QCU_MISC_CBREXP_BCN |
|
||||
AR5K_QCU_MISC_BCN_ENABLE);
|
||||
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
|
||||
(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
|
||||
AR5K_DCU_MISC_ARBLOCK_CTL_S) |
|
||||
AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
|
||||
AR5K_DCU_MISC_BCN_ENABLE);
|
||||
|
||||
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
|
||||
(AR5K_TUNE_SW_BEACON_RESP -
|
||||
AR5K_TUNE_DMA_BEACON_RESP) -
|
||||
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
|
||||
AR5K_QCU_RDYTIMECFG_ENABLE,
|
||||
AR5K_QUEUE_RDYTIMECFG(queue));
|
||||
break;
|
||||
|
||||
case AR5K_TX_QUEUE_CAB:
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_FRSHED_DBA_GT |
|
||||
AR5K_QCU_MISC_CBREXP |
|
||||
AR5K_QCU_MISC_CBREXP_BCN);
|
||||
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
|
||||
(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
|
||||
AR5K_DCU_MISC_ARBLOCK_CTL_S));
|
||||
break;
|
||||
|
||||
case AR5K_TX_QUEUE_UAPSD:
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
|
||||
AR5K_QCU_MISC_CBREXP);
|
||||
break;
|
||||
|
||||
case AR5K_TX_QUEUE_DATA:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable interrupts for this tx queue
|
||||
* in the secondary interrupt mask registers
|
||||
*/
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
|
||||
|
||||
if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
|
||||
AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
|
||||
|
||||
|
||||
/* Update secondary interrupt mask registers */
|
||||
ah->ah_txq_imr_txok &= ah->ah_txq_status;
|
||||
ah->ah_txq_imr_txerr &= ah->ah_txq_status;
|
||||
ah->ah_txq_imr_txurn &= ah->ah_txq_status;
|
||||
ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
|
||||
ah->ah_txq_imr_txeol &= ah->ah_txq_status;
|
||||
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
|
||||
AR5K_SIMR0_QCU_TXOK) |
|
||||
AR5K_REG_SM(ah->ah_txq_imr_txdesc,
|
||||
AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
|
||||
AR5K_SIMR1_QCU_TXERR) |
|
||||
AR5K_REG_SM(ah->ah_txq_imr_txeol,
|
||||
AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
|
||||
ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
|
||||
AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get slot time from DCU
|
||||
*/
|
||||
unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
|
||||
AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
|
||||
else
|
||||
return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set slot time on DCU
|
||||
*/
|
||||
int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
|
||||
{
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
|
||||
ah->ah_turbo), AR5K_SLOT_TIME);
|
||||
else
|
||||
ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -976,98 +976,6 @@
|
|||
*/
|
||||
#define AR5K_EEPROM_BASE 0x6000
|
||||
|
||||
/*
|
||||
* Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
|
||||
*/
|
||||
#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */
|
||||
#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */
|
||||
#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */
|
||||
#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */
|
||||
#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */
|
||||
|
||||
#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */
|
||||
#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */
|
||||
#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008
|
||||
#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */
|
||||
#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020
|
||||
#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */
|
||||
#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080
|
||||
#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */
|
||||
#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200
|
||||
#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */
|
||||
#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800
|
||||
#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */
|
||||
#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000
|
||||
#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */
|
||||
#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000
|
||||
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
|
||||
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
|
||||
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
|
||||
#define AR5K_EEPROM_INFO_CKSUM 0xffff
|
||||
#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n))
|
||||
|
||||
#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */
|
||||
#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */
|
||||
#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */
|
||||
#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */
|
||||
#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
|
||||
#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
|
||||
#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */
|
||||
#define AR5K_EEPROM_VERSION_4_3 0x4003
|
||||
#define AR5K_EEPROM_VERSION_4_4 0x4004
|
||||
#define AR5K_EEPROM_VERSION_4_5 0x4005
|
||||
#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
|
||||
#define AR5K_EEPROM_VERSION_4_7 0x4007
|
||||
|
||||
#define AR5K_EEPROM_MODE_11A 0
|
||||
#define AR5K_EEPROM_MODE_11B 1
|
||||
#define AR5K_EEPROM_MODE_11G 2
|
||||
|
||||
#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */
|
||||
#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
|
||||
#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */
|
||||
#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */
|
||||
#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7)
|
||||
#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */
|
||||
#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */
|
||||
|
||||
#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c
|
||||
#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2
|
||||
#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002
|
||||
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
|
||||
|
||||
/* Newer EEPROMs are using a different offset */
|
||||
#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
|
||||
(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
|
||||
|
||||
#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
|
||||
#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff))
|
||||
#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff))
|
||||
|
||||
/* calibration settings */
|
||||
#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
|
||||
#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
|
||||
#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
|
||||
#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */
|
||||
|
||||
/* [3.1 - 3.3] */
|
||||
#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec
|
||||
#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed
|
||||
|
||||
/* Misc values available since EEPROM 4.0 */
|
||||
#define AR5K_EEPROM_MISC0 0x00c4
|
||||
#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff)
|
||||
#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3)
|
||||
#define AR5K_EEPROM_MISC1 0x00c5
|
||||
#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff)
|
||||
#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1)
|
||||
|
||||
/*
|
||||
* EEPROM data register
|
||||
*/
|
||||
|
@ -1950,13 +1858,13 @@
|
|||
#define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */
|
||||
|
||||
/*
|
||||
* Desired size register
|
||||
* Desired ADC/PGA size register
|
||||
* (for more infos read ANI patent)
|
||||
*/
|
||||
#define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */
|
||||
#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */
|
||||
#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */
|
||||
#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size (?) */
|
||||
#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size */
|
||||
|
||||
/*
|
||||
* PHY signal register
|
||||
|
|
|
@ -0,0 +1,925 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
|
||||
* Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
|
||||
* Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
|
||||
* Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
|
||||
* Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _ATH5K_RESET
|
||||
|
||||
/*****************************\
|
||||
Reset functions and helpers
|
||||
\*****************************/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "ath5k.h"
|
||||
#include "reg.h"
|
||||
#include "base.h"
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
|
||||
*
|
||||
* @ah: the &struct ath5k_hw
|
||||
* @channel: the currently set channel upon reset
|
||||
*
|
||||
* Write the OFDM timings for the AR5212 upon reset. This is a helper for
|
||||
* ath5k_hw_reset(). This seems to tune the PLL a specified frequency
|
||||
* depending on the bandwidth of the channel.
|
||||
*
|
||||
*/
|
||||
static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
|
||||
struct ieee80211_channel *channel)
|
||||
{
|
||||
/* Get exponent and mantissa and set it */
|
||||
u32 coef_scaled, coef_exp, coef_man,
|
||||
ds_coef_exp, ds_coef_man, clock;
|
||||
|
||||
if (!(ah->ah_version == AR5K_AR5212) ||
|
||||
!(channel->hw_value & CHANNEL_OFDM))
|
||||
BUG();
|
||||
|
||||
/* Seems there are two PLLs, one for baseband sampling and one
|
||||
* for tuning. Tuning basebands are 40 MHz or 80MHz when in
|
||||
* turbo. */
|
||||
clock = channel->hw_value & CHANNEL_TURBO ? 80 : 40;
|
||||
coef_scaled = ((5 * (clock << 24)) / 2) /
|
||||
channel->center_freq;
|
||||
|
||||
for (coef_exp = 31; coef_exp > 0; coef_exp--)
|
||||
if ((coef_scaled >> coef_exp) & 0x1)
|
||||
break;
|
||||
|
||||
if (!coef_exp)
|
||||
return -EINVAL;
|
||||
|
||||
coef_exp = 14 - (coef_exp - 24);
|
||||
coef_man = coef_scaled +
|
||||
(1 << (24 - coef_exp - 1));
|
||||
ds_coef_man = coef_man >> (24 - coef_exp);
|
||||
ds_coef_exp = coef_exp - 16;
|
||||
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
|
||||
AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
|
||||
AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* index into rates for control rates, we can set it up like this because
|
||||
* this is only used for AR5212 and we know it supports G mode
|
||||
*/
|
||||
static int control_rates[] =
|
||||
{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
|
||||
|
||||
/**
|
||||
* ath5k_hw_write_rate_duration - set rate duration during hw resets
|
||||
*
|
||||
* @ah: the &struct ath5k_hw
|
||||
* @mode: one of enum ath5k_driver_mode
|
||||
*
|
||||
* Write the rate duration table upon hw reset. This is a helper for
|
||||
* ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout for
|
||||
* the hardware for the current mode for each rate. The rates which are capable
|
||||
* of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have another
|
||||
* register for the short preamble ACK timeout calculation.
|
||||
*/
|
||||
static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ath5k_softc *sc = ah->ah_sc;
|
||||
struct ieee80211_rate *rate;
|
||||
unsigned int i;
|
||||
|
||||
/* Write rate duration table */
|
||||
for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) {
|
||||
u32 reg;
|
||||
u16 tx_time;
|
||||
|
||||
rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]];
|
||||
|
||||
/* Set ACK timeout */
|
||||
reg = AR5K_RATE_DUR(rate->hw_value);
|
||||
|
||||
/* An ACK frame consists of 10 bytes. If you add the FCS,
|
||||
* which ieee80211_generic_frame_duration() adds,
|
||||
* its 14 bytes. Note we use the control rate and not the
|
||||
* actual rate for this rate. See mac80211 tx.c
|
||||
* ieee80211_duration() for a brief description of
|
||||
* what rate we should choose to TX ACKs. */
|
||||
tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
|
||||
sc->vif, 10, rate));
|
||||
|
||||
ath5k_hw_reg_write(ah, tx_time, reg);
|
||||
|
||||
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We're not distinguishing short preamble here,
|
||||
* This is true, all we'll get is a longer value here
|
||||
* which is not necessarilly bad. We could use
|
||||
* export ieee80211_frame_duration() but that needs to be
|
||||
* fixed first to be properly used by mac802111 drivers:
|
||||
*
|
||||
* - remove erp stuff and let the routine figure ofdm
|
||||
* erp rates
|
||||
* - remove passing argument ieee80211_local as
|
||||
* drivers don't have access to it
|
||||
* - move drivers using ieee80211_generic_frame_duration()
|
||||
* to this
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, tx_time,
|
||||
reg + (AR5K_SET_SHORT_PREAMBLE << 2));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset chipset
|
||||
*/
|
||||
static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
|
||||
{
|
||||
int ret;
|
||||
u32 mask = val ? val : ~0U;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/* Read-and-clear RX Descriptor Pointer*/
|
||||
ath5k_hw_reg_read(ah, AR5K_RXDP);
|
||||
|
||||
/*
|
||||
* Reset the device and wait until success
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
|
||||
|
||||
/* Wait at least 128 PCI clocks */
|
||||
udelay(15);
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210) {
|
||||
val &= AR5K_RESET_CTL_CHIP;
|
||||
mask &= AR5K_RESET_CTL_CHIP;
|
||||
} else {
|
||||
val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
|
||||
mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
|
||||
}
|
||||
|
||||
ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
|
||||
|
||||
/*
|
||||
* Reset configuration register (for hw byte-swap). Note that this
|
||||
* is only set for big endian. We do the necessary magic in
|
||||
* AR5K_INIT_CFG.
|
||||
*/
|
||||
if ((val & AR5K_RESET_CTL_PCU) == 0)
|
||||
ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sleep control
|
||||
*/
|
||||
int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
|
||||
bool set_chip, u16 sleep_duration)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 staid, data;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
|
||||
|
||||
switch (mode) {
|
||||
case AR5K_PM_AUTO:
|
||||
staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
|
||||
/* fallthrough */
|
||||
case AR5K_PM_NETWORK_SLEEP:
|
||||
if (set_chip)
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_SLEEP_CTL_SLE_ALLOW |
|
||||
sleep_duration,
|
||||
AR5K_SLEEP_CTL);
|
||||
|
||||
staid |= AR5K_STA_ID1_PWR_SV;
|
||||
break;
|
||||
|
||||
case AR5K_PM_FULL_SLEEP:
|
||||
if (set_chip)
|
||||
ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
|
||||
AR5K_SLEEP_CTL);
|
||||
|
||||
staid |= AR5K_STA_ID1_PWR_SV;
|
||||
break;
|
||||
|
||||
case AR5K_PM_AWAKE:
|
||||
|
||||
staid &= ~AR5K_STA_ID1_PWR_SV;
|
||||
|
||||
if (!set_chip)
|
||||
goto commit;
|
||||
|
||||
/* Preserve sleep duration */
|
||||
data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
|
||||
if (data & 0xffc00000)
|
||||
data = 0;
|
||||
else
|
||||
data = data & 0xfffcffff;
|
||||
|
||||
ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
||||
udelay(15);
|
||||
|
||||
for (i = 50; i > 0; i--) {
|
||||
/* Check if the chip did wake up */
|
||||
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
|
||||
AR5K_PCICFG_SPWR_DN) == 0)
|
||||
break;
|
||||
|
||||
/* Wait a bit and retry */
|
||||
udelay(200);
|
||||
ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
||||
}
|
||||
|
||||
/* Fail if the chip didn't wake up */
|
||||
if (i <= 0)
|
||||
return -EIO;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
commit:
|
||||
ah->ah_power_mode = mode;
|
||||
ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bring up MAC + PHY Chips
|
||||
*/
|
||||
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
||||
{
|
||||
struct pci_dev *pdev = ah->ah_sc->pdev;
|
||||
u32 turbo, mode, clock, bus_flags;
|
||||
int ret;
|
||||
|
||||
turbo = 0;
|
||||
mode = 0;
|
||||
clock = 0;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
/* Wakeup the device */
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
/*
|
||||
* Get channel mode flags
|
||||
*/
|
||||
|
||||
if (ah->ah_radio >= AR5K_RF5112) {
|
||||
mode = AR5K_PHY_MODE_RAD_RF5112;
|
||||
clock = AR5K_PHY_PLL_RF5112;
|
||||
} else {
|
||||
mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/
|
||||
clock = AR5K_PHY_PLL_RF5111; /*Zero*/
|
||||
}
|
||||
|
||||
if (flags & CHANNEL_2GHZ) {
|
||||
mode |= AR5K_PHY_MODE_FREQ_2GHZ;
|
||||
clock |= AR5K_PHY_PLL_44MHZ;
|
||||
|
||||
if (flags & CHANNEL_CCK) {
|
||||
mode |= AR5K_PHY_MODE_MOD_CCK;
|
||||
} else if (flags & CHANNEL_OFDM) {
|
||||
/* XXX Dynamic OFDM/CCK is not supported by the
|
||||
* AR5211 so we set MOD_OFDM for plain g (no
|
||||
* CCK headers) operation. We need to test
|
||||
* this, 5211 might support ofdm-only g after
|
||||
* all, there are also initial register values
|
||||
* in the code for g mode (see initvals.c). */
|
||||
if (ah->ah_version == AR5K_AR5211)
|
||||
mode |= AR5K_PHY_MODE_MOD_OFDM;
|
||||
else
|
||||
mode |= AR5K_PHY_MODE_MOD_DYN;
|
||||
} else {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid radio modulation mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (flags & CHANNEL_5GHZ) {
|
||||
mode |= AR5K_PHY_MODE_FREQ_5GHZ;
|
||||
clock |= AR5K_PHY_PLL_40MHZ;
|
||||
|
||||
if (flags & CHANNEL_OFDM)
|
||||
mode |= AR5K_PHY_MODE_MOD_OFDM;
|
||||
else {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid radio modulation mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flags & CHANNEL_TURBO)
|
||||
turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
|
||||
} else { /* Reset the device */
|
||||
|
||||
/* ...enable Atheros turbo mode if requested */
|
||||
if (flags & CHANNEL_TURBO)
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
|
||||
AR5K_PHY_TURBO);
|
||||
}
|
||||
|
||||
/* reseting PCI on PCI-E cards results card to hang
|
||||
* and always return 0xffff... so we ingore that flag
|
||||
* for PCI-E cards */
|
||||
bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
||||
|
||||
/* Reset chipset */
|
||||
ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
||||
AR5K_RESET_CTL_BASEBAND | bus_flags);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ah->ah_version == AR5K_AR5210)
|
||||
udelay(2300);
|
||||
|
||||
/* ...wakeup again!*/
|
||||
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ...final warm reset */
|
||||
if (ath5k_hw_nic_reset(ah, 0)) {
|
||||
ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
/* ...set the PHY operating mode */
|
||||
ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
|
||||
udelay(300);
|
||||
|
||||
ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
|
||||
ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main reset function
|
||||
*/
|
||||
int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
|
||||
struct ieee80211_channel *channel, bool change_channel)
|
||||
{
|
||||
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
|
||||
struct pci_dev *pdev = ah->ah_sc->pdev;
|
||||
u32 data, s_seq, s_ant, s_led[3], dma_size;
|
||||
unsigned int i, mode, freq, ee_mode, ant[2];
|
||||
int ret;
|
||||
|
||||
ATH5K_TRACE(ah->ah_sc);
|
||||
|
||||
s_seq = 0;
|
||||
s_ant = 0;
|
||||
ee_mode = 0;
|
||||
freq = 0;
|
||||
mode = 0;
|
||||
|
||||
/*
|
||||
* Save some registers before a reset
|
||||
*/
|
||||
/*DCU/Antenna selection not available on 5210*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
if (change_channel) {
|
||||
/* Seq number for queue 0 -do this for all queues ? */
|
||||
s_seq = ath5k_hw_reg_read(ah,
|
||||
AR5K_QUEUE_DFS_SEQNUM(0));
|
||||
/*Default antenna*/
|
||||
s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
|
||||
}
|
||||
}
|
||||
|
||||
/*GPIOs*/
|
||||
s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
|
||||
s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
|
||||
s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
|
||||
|
||||
if (change_channel && ah->ah_rf_banks != NULL)
|
||||
ath5k_hw_get_rf_gain(ah);
|
||||
|
||||
|
||||
/*Wakeup the device*/
|
||||
ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Initialize operating mode
|
||||
*/
|
||||
ah->ah_op_mode = op_mode;
|
||||
|
||||
/*
|
||||
* 5111/5112 Settings
|
||||
* 5210 only comes with RF5110
|
||||
*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
if (ah->ah_radio != AR5K_RF5111 &&
|
||||
ah->ah_radio != AR5K_RF5112 &&
|
||||
ah->ah_radio != AR5K_RF5413 &&
|
||||
ah->ah_radio != AR5K_RF2413 &&
|
||||
ah->ah_radio != AR5K_RF2425) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid phy radio: %u\n", ah->ah_radio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (channel->hw_value & CHANNEL_MODES) {
|
||||
case CHANNEL_A:
|
||||
mode = AR5K_MODE_11A;
|
||||
freq = AR5K_INI_RFGAIN_5GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11A;
|
||||
break;
|
||||
case CHANNEL_G:
|
||||
mode = AR5K_MODE_11G;
|
||||
freq = AR5K_INI_RFGAIN_2GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11G;
|
||||
break;
|
||||
case CHANNEL_B:
|
||||
mode = AR5K_MODE_11B;
|
||||
freq = AR5K_INI_RFGAIN_2GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11B;
|
||||
break;
|
||||
case CHANNEL_T:
|
||||
mode = AR5K_MODE_11A_TURBO;
|
||||
freq = AR5K_INI_RFGAIN_5GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11A;
|
||||
break;
|
||||
/*Is this ok on 5211 too ?*/
|
||||
case CHANNEL_TG:
|
||||
mode = AR5K_MODE_11G_TURBO;
|
||||
freq = AR5K_INI_RFGAIN_2GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11G;
|
||||
break;
|
||||
case CHANNEL_XR:
|
||||
if (ah->ah_version == AR5K_AR5211) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"XR mode not available on 5211");
|
||||
return -EINVAL;
|
||||
}
|
||||
mode = AR5K_MODE_XR;
|
||||
freq = AR5K_INI_RFGAIN_5GHZ;
|
||||
ee_mode = AR5K_EEPROM_MODE_11A;
|
||||
break;
|
||||
default:
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"invalid channel: %d\n", channel->center_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* PHY access enable */
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
|
||||
|
||||
}
|
||||
|
||||
ret = ath5k_hw_write_initvals(ah, mode, change_channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* 5211/5212 Specific
|
||||
*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
/*
|
||||
* Write initial RF gain settings
|
||||
* This should work for both 5111/5112
|
||||
*/
|
||||
ret = ath5k_hw_rfgain(ah, freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdelay(1);
|
||||
|
||||
/*
|
||||
* Write some more initial register settings
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
|
||||
|
||||
if (channel->hw_value == CHANNEL_G)
|
||||
if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
|
||||
ath5k_hw_reg_write(ah, 0x00f80d80,
|
||||
0x994c);
|
||||
else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
|
||||
ath5k_hw_reg_write(ah, 0x00380140,
|
||||
0x994c);
|
||||
else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
|
||||
ath5k_hw_reg_write(ah, 0x00fc0ec0,
|
||||
0x994c);
|
||||
else /* 2425 */
|
||||
ath5k_hw_reg_write(ah, 0x00fc0fc0,
|
||||
0x994c);
|
||||
else
|
||||
ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
|
||||
|
||||
/* Some bits are disabled here, we know nothing about
|
||||
* register 0xa228 yet, most of the times this ends up
|
||||
* with a value 0x9b5 -haven't seen any dump with
|
||||
* a different value- */
|
||||
/* Got this from decompiling binary HAL */
|
||||
data = ath5k_hw_reg_read(ah, 0xa228);
|
||||
data &= 0xfffffdff;
|
||||
ath5k_hw_reg_write(ah, data, 0xa228);
|
||||
|
||||
data = ath5k_hw_reg_read(ah, 0xa228);
|
||||
data &= 0xfffe03ff;
|
||||
ath5k_hw_reg_write(ah, data, 0xa228);
|
||||
data = 0;
|
||||
|
||||
/* Just write 0x9b5 ? */
|
||||
/* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
|
||||
ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
|
||||
ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
|
||||
ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
|
||||
}
|
||||
|
||||
/* Fix for first revision of the RF5112 RF chipset */
|
||||
if (ah->ah_radio >= AR5K_RF5112 &&
|
||||
ah->ah_radio_5ghz_revision <
|
||||
AR5K_SREV_RAD_5112A) {
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
|
||||
AR5K_PHY_CCKTXCTL);
|
||||
if (channel->hw_value & CHANNEL_5GHZ)
|
||||
data = 0xffb81020;
|
||||
else
|
||||
data = 0xffb80d20;
|
||||
ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
|
||||
data = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set TX power (FIXME)
|
||||
*/
|
||||
ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write rate duration table only on AR5212 and if
|
||||
* virtual interface has already been brought up
|
||||
* XXX: rethink this after new mode changes to
|
||||
* mac80211 are integrated */
|
||||
if (ah->ah_version == AR5K_AR5212 &&
|
||||
ah->ah_sc->vif != NULL)
|
||||
ath5k_hw_write_rate_duration(ah, mode);
|
||||
|
||||
/*
|
||||
* Write RF registers
|
||||
*/
|
||||
ret = ath5k_hw_rfregs(ah, channel, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Configure additional registers
|
||||
*/
|
||||
|
||||
/* Write OFDM timings on 5212*/
|
||||
if (ah->ah_version == AR5K_AR5212 &&
|
||||
channel->hw_value & CHANNEL_OFDM) {
|
||||
ret = ath5k_hw_write_ofdm_timings(ah, channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*Enable/disable 802.11b mode on 5111
|
||||
(enable 2111 frequency converter + CCK)*/
|
||||
if (ah->ah_radio == AR5K_RF5111) {
|
||||
if (mode == AR5K_MODE_11B)
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
|
||||
AR5K_TXCFG_B_MODE);
|
||||
else
|
||||
AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
|
||||
AR5K_TXCFG_B_MODE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set channel and calibrate the PHY
|
||||
*/
|
||||
ret = ath5k_hw_channel(ah, channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set antenna mode */
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
|
||||
ah->ah_antenna[ee_mode][0], 0xfffffc06);
|
||||
|
||||
/*
|
||||
* In case a fixed antenna was set as default
|
||||
* write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
|
||||
* registers.
|
||||
*/
|
||||
if (s_ant != 0) {
|
||||
if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
|
||||
ant[0] = ant[1] = AR5K_ANT_FIXED_A;
|
||||
else /* 2 - Aux */
|
||||
ant[0] = ant[1] = AR5K_ANT_FIXED_B;
|
||||
} else {
|
||||
ant[0] = AR5K_ANT_FIXED_A;
|
||||
ant[1] = AR5K_ANT_FIXED_B;
|
||||
}
|
||||
|
||||
ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
|
||||
AR5K_PHY_ANT_SWITCH_TABLE_0);
|
||||
ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
|
||||
AR5K_PHY_ANT_SWITCH_TABLE_1);
|
||||
|
||||
/* Commit values from EEPROM */
|
||||
if (ah->ah_radio == AR5K_RF5111)
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
|
||||
AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
|
||||
AR5K_PHY_NFTHRES);
|
||||
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
|
||||
(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
|
||||
0xffffc07f);
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
|
||||
(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
|
||||
0xfffc0fff);
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
|
||||
(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
|
||||
((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
|
||||
0xffff0000);
|
||||
|
||||
ath5k_hw_reg_write(ah,
|
||||
(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
|
||||
(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
|
||||
(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
|
||||
(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
|
||||
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
|
||||
ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
|
||||
(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
|
||||
AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
|
||||
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
|
||||
AR5K_PHY_IQ_CORR_ENABLE |
|
||||
(ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
|
||||
ee->ee_q_cal[ee_mode]);
|
||||
|
||||
if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
|
||||
AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
|
||||
ee->ee_margin_tx_rx[ee_mode]);
|
||||
|
||||
} else {
|
||||
mdelay(1);
|
||||
/* Disable phy and wait */
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore saved values
|
||||
*/
|
||||
/*DCU/Antenna selection not available on 5210*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
|
||||
ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
|
||||
}
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
|
||||
ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
|
||||
ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
/* XXX: add ah->aid once mac80211 gives this to us */
|
||||
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
|
||||
|
||||
ath5k_hw_set_opmode(ah);
|
||||
/*PISR/SISR Not available on 5210*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
|
||||
/* If we later allow tuning for this, store into sc structure */
|
||||
data = AR5K_TUNE_RSSI_THRES |
|
||||
AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
|
||||
ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Rx/Tx DMA Configuration
|
||||
*
|
||||
* Set maximum DMA size (512) except for PCI-E cards since
|
||||
* it causes rx overruns and tx errors (tested on 5424 but since
|
||||
* rx overruns also occur on 5416/5418 with madwifi we set 128
|
||||
* for all PCI-E cards to be safe).
|
||||
*
|
||||
* In dumps this is 128 for allchips.
|
||||
*
|
||||
* XXX: need to check 5210 for this
|
||||
* TODO: Check out tx triger level, it's always 64 on dumps but I
|
||||
* guess we can tweak it and see how it goes ;-)
|
||||
*/
|
||||
dma_size = (pdev->is_pcie) ? AR5K_DMASIZE_128B : AR5K_DMASIZE_512B;
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
|
||||
AR5K_TXCFG_SDMAMR, dma_size);
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
|
||||
AR5K_RXCFG_SDMAMW, dma_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the PHY and wait until completion
|
||||
*/
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
|
||||
|
||||
/*
|
||||
* On 5211+ read activation -> rx delay
|
||||
* and use it.
|
||||
*/
|
||||
if (ah->ah_version != AR5K_AR5210) {
|
||||
data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
|
||||
AR5K_PHY_RX_DELAY_M;
|
||||
data = (channel->hw_value & CHANNEL_CCK) ?
|
||||
((data << 2) / 22) : (data / 10);
|
||||
|
||||
udelay(100 + (2 * data));
|
||||
data = 0;
|
||||
} else {
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform ADC test (?)
|
||||
*/
|
||||
data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
|
||||
for (i = 0; i <= 20; i++) {
|
||||
if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
|
||||
break;
|
||||
udelay(200);
|
||||
}
|
||||
ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
|
||||
data = 0;
|
||||
|
||||
/*
|
||||
* Start automatic gain calibration
|
||||
*
|
||||
* During AGC calibration RX path is re-routed to
|
||||
* a signal detector so we don't receive anything.
|
||||
*
|
||||
* This method is used to calibrate some static offsets
|
||||
* used together with on-the fly I/Q calibration (the
|
||||
* one performed via ath5k_hw_phy_calibrate), that doesn't
|
||||
* interrupt rx path.
|
||||
*
|
||||
* If we are in a noisy environment AGC calibration may time
|
||||
* out.
|
||||
*/
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
|
||||
AR5K_PHY_AGCCTL_CAL);
|
||||
|
||||
/* At the same time start I/Q calibration for QAM constellation
|
||||
* -no need for CCK- */
|
||||
ah->ah_calibration = false;
|
||||
if (!(mode == AR5K_MODE_11B)) {
|
||||
ah->ah_calibration = true;
|
||||
AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
|
||||
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
|
||||
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
|
||||
AR5K_PHY_IQ_RUN);
|
||||
}
|
||||
|
||||
/* Wait for gain calibration to finish (we check for I/Q calibration
|
||||
* during ath5k_phy_calibrate) */
|
||||
if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
|
||||
AR5K_PHY_AGCCTL_CAL, 0, false)) {
|
||||
ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
|
||||
channel->center_freq);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start noise floor calibration
|
||||
*
|
||||
* If we run NF calibration before AGC, it always times out.
|
||||
* Binary HAL starts NF and AGC calibration at the same time
|
||||
* and only waits for AGC to finish. I believe that's wrong because
|
||||
* during NF calibration, rx path is also routed to a detector, so if
|
||||
* it doesn't finish we won't have RX.
|
||||
*
|
||||
* XXX: Find an interval that's OK for all cards...
|
||||
*/
|
||||
ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Reset queues and start beacon timers at the end of the reset routine
|
||||
*/
|
||||
for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
|
||||
/*No QCU on 5210*/
|
||||
if (ah->ah_version != AR5K_AR5210)
|
||||
AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
|
||||
|
||||
ret = ath5k_hw_reset_tx_queue(ah, i);
|
||||
if (ret) {
|
||||
ATH5K_ERR(ah->ah_sc,
|
||||
"failed to reset TX queue #%d\n", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pre-enable interrupts on 5211/5212*/
|
||||
if (ah->ah_version != AR5K_AR5210)
|
||||
ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX |
|
||||
AR5K_INT_FATAL);
|
||||
|
||||
/*
|
||||
* Set RF kill flags if supported by the device (read from the EEPROM)
|
||||
* Disable gpio_intr for now since it results system hang.
|
||||
* TODO: Handle this in ath5k_intr
|
||||
*/
|
||||
#if 0
|
||||
if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
|
||||
ath5k_hw_set_gpio_input(ah, 0);
|
||||
ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
|
||||
if (ah->ah_gpio[0] == 0)
|
||||
ath5k_hw_set_gpio_intr(ah, 0, 1);
|
||||
else
|
||||
ath5k_hw_set_gpio_intr(ah, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the 32MHz reference clock on 5212 phy clock sleep register
|
||||
*
|
||||
* TODO: Find out how to switch to external 32Khz clock to save power
|
||||
*/
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
|
||||
ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
|
||||
ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
|
||||
|
||||
data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
|
||||
data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
|
||||
0x00000f80 : 0x00001380 ;
|
||||
ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if (ah->ah_version == AR5K_AR5212) {
|
||||
ath5k_hw_reg_write(ah, 0x000100aa, 0x8118);
|
||||
ath5k_hw_reg_write(ah, 0x00003210, 0x811c);
|
||||
ath5k_hw_reg_write(ah, 0x00000052, 0x8108);
|
||||
if (ah->ah_mac_srev >= AR5K_SREV_VER_AR2413)
|
||||
ath5k_hw_reg_write(ah, 0x00000004, 0x8120);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable beacons and reset the register
|
||||
*/
|
||||
AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
|
||||
AR5K_BEACON_RESET_TSF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef _ATH5K_RESET
|
|
@ -1,6 +1,9 @@
|
|||
config ATH9K
|
||||
tristate "Atheros 802.11n wireless cards support"
|
||||
depends on PCI && MAC80211 && WLAN_80211
|
||||
select MAC80211_LEDS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---help---
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
|
||||
|
|
|
@ -1482,6 +1482,11 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
SET_IEEE80211_DEV(hw, &pdev->dev);
|
||||
pci_set_drvdata(pdev, hw);
|
||||
|
||||
|
|
|
@ -80,6 +80,18 @@ config B43_NPHY
|
|||
|
||||
SAY N.
|
||||
|
||||
config B43_PHY_LP
|
||||
bool "IEEE 802.11g LP-PHY support (BROKEN)"
|
||||
depends on B43 && EXPERIMENTAL && BROKEN
|
||||
---help---
|
||||
Support for the LP-PHY.
|
||||
The LP-PHY is an IEEE 802.11g based PHY built into some notebooks
|
||||
and embedded devices.
|
||||
|
||||
THIS IS BROKEN AND DOES NOT WORK YET.
|
||||
|
||||
SAY N.
|
||||
|
||||
# This config option automatically enables b43 LEDS support,
|
||||
# if it's possible.
|
||||
config B43_LEDS
|
||||
|
|
|
@ -4,7 +4,8 @@ b43-$(CONFIG_B43_NPHY) += tables_nphy.o
|
|||
b43-y += phy_common.o
|
||||
b43-y += phy_g.o
|
||||
b43-y += phy_a.o
|
||||
b43-$(CONFIG_B43_NPHY) += nphy.o
|
||||
b43-$(CONFIG_B43_NPHY) += phy_n.o
|
||||
b43-$(CONFIG_B43_PHY_LP) += phy_lp.o
|
||||
b43-y += sysfs.o
|
||||
b43-y += xmit.o
|
||||
b43-y += lo.o
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "debugfs.h"
|
||||
#include "phy_common.h"
|
||||
#include "phy_g.h"
|
||||
#include "nphy.h"
|
||||
#include "phy_n.h"
|
||||
#include "dma.h"
|
||||
#include "pio.h"
|
||||
#include "sysfs.h"
|
||||
|
@ -1052,23 +1052,6 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
|
|||
}
|
||||
}
|
||||
|
||||
/* Turn the Analog ON/OFF */
|
||||
static void b43_switch_analog(struct b43_wldev *dev, int on)
|
||||
{
|
||||
switch (dev->phy.type) {
|
||||
case B43_PHYTYPE_A:
|
||||
case B43_PHYTYPE_G:
|
||||
b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
|
||||
on ? 0 : 0x7FFF);
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
|
||||
{
|
||||
u32 tmslow;
|
||||
|
@ -1091,8 +1074,12 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
|
|||
ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
|
||||
msleep(1);
|
||||
|
||||
/* Turn Analog ON */
|
||||
b43_switch_analog(dev, 1);
|
||||
/* Turn Analog ON, but only if we already know the PHY-type.
|
||||
* This protects against very early setup where we don't know the
|
||||
* PHY-type, yet. wireless_core_reset will be called once again later,
|
||||
* when we know the PHY-type. */
|
||||
if (dev->phy.ops)
|
||||
dev->phy.ops->switch_analog(dev, 1);
|
||||
|
||||
macctl = b43_read32(dev, B43_MMIO_MACCTL);
|
||||
macctl &= ~B43_MACCTL_GMODE;
|
||||
|
@ -2694,6 +2681,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
|
|||
/* This is the opposite of b43_chip_init() */
|
||||
static void b43_chip_exit(struct b43_wldev *dev)
|
||||
{
|
||||
b43_phy_exit(dev);
|
||||
b43_gpio_cleanup(dev);
|
||||
/* firmware is released later */
|
||||
}
|
||||
|
@ -2730,7 +2718,8 @@ static int b43_chip_init(struct b43_wldev *dev)
|
|||
if (err)
|
||||
goto err_gpio_clean;
|
||||
|
||||
b43_write16(dev, 0x03E6, 0x0000);
|
||||
/* Turn the Analog on and initialize the PHY. */
|
||||
phy->ops->switch_analog(dev, 1);
|
||||
err = b43_phy_init(dev);
|
||||
if (err)
|
||||
goto err_gpio_clean;
|
||||
|
@ -3947,12 +3936,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
|||
b43_dma_free(dev);
|
||||
b43_pio_free(dev);
|
||||
b43_chip_exit(dev);
|
||||
b43_switch_analog(dev, 0);
|
||||
dev->phy.ops->switch_analog(dev, 0);
|
||||
if (dev->wl->current_beacon) {
|
||||
dev_kfree_skb_any(dev->wl->current_beacon);
|
||||
dev->wl->current_beacon = NULL;
|
||||
}
|
||||
b43_phy_exit(dev);
|
||||
|
||||
ssb_device_disable(dev->dev, 0);
|
||||
ssb_bus_may_powerdown(dev->dev->bus);
|
||||
|
@ -3979,24 +3967,23 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
|||
b43_wireless_core_reset(dev, tmp);
|
||||
}
|
||||
|
||||
/* Reset all data structures. */
|
||||
setup_struct_wldev_for_init(dev);
|
||||
err = b43_phy_operations_setup(dev);
|
||||
if (err)
|
||||
goto err_busdown;
|
||||
phy->ops->prepare_structs(dev);
|
||||
|
||||
/* Enable IRQ routing to this device. */
|
||||
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
|
||||
|
||||
b43_imcfglo_timeouts_workaround(dev);
|
||||
b43_bluetooth_coext_disable(dev);
|
||||
if (phy->ops->prepare) {
|
||||
err = phy->ops->prepare(dev);
|
||||
if (phy->ops->prepare_hardware) {
|
||||
err = phy->ops->prepare_hardware(dev);
|
||||
if (err)
|
||||
goto err_phy_exit;
|
||||
goto err_busdown;
|
||||
}
|
||||
err = b43_chip_init(dev);
|
||||
if (err)
|
||||
goto err_phy_exit;
|
||||
goto err_busdown;
|
||||
b43_shm_write16(dev, B43_SHM_SHARED,
|
||||
B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
|
||||
hf = b43_hf_read(dev);
|
||||
|
@ -4064,8 +4051,6 @@ out:
|
|||
|
||||
err_chip_exit:
|
||||
b43_chip_exit(dev);
|
||||
err_phy_exit:
|
||||
b43_phy_exit(dev);
|
||||
err_busdown:
|
||||
ssb_bus_may_powerdown(bus);
|
||||
B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
|
||||
|
@ -4342,6 +4327,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
|
|||
/* We release firmware that late to not be required to re-request
|
||||
* is all the time when we reinit the core. */
|
||||
b43_release_firmware(dev);
|
||||
b43_phy_free(dev);
|
||||
}
|
||||
|
||||
static int b43_wireless_core_attach(struct b43_wldev *dev)
|
||||
|
@ -4415,29 +4401,35 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
err = b43_phy_allocate(dev);
|
||||
if (err)
|
||||
goto err_powerdown;
|
||||
|
||||
dev->phy.gmode = have_2ghz_phy;
|
||||
tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
|
||||
b43_wireless_core_reset(dev, tmp);
|
||||
|
||||
err = b43_validate_chipaccess(dev);
|
||||
if (err)
|
||||
goto err_powerdown;
|
||||
goto err_phy_free;
|
||||
err = b43_setup_bands(dev, have_2ghz_phy, have_5ghz_phy);
|
||||
if (err)
|
||||
goto err_powerdown;
|
||||
goto err_phy_free;
|
||||
|
||||
/* Now set some default "current_dev" */
|
||||
if (!wl->current_dev)
|
||||
wl->current_dev = dev;
|
||||
INIT_WORK(&dev->restart_work, b43_chip_reset);
|
||||
|
||||
b43_switch_analog(dev, 0);
|
||||
dev->phy.ops->switch_analog(dev, 0);
|
||||
ssb_device_disable(dev->dev, 0);
|
||||
ssb_bus_may_powerdown(bus);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
err_phy_free:
|
||||
b43_phy_free(dev);
|
||||
err_powerdown:
|
||||
ssb_bus_may_powerdown(bus);
|
||||
return err;
|
||||
|
@ -4569,6 +4561,13 @@ static int b43_wireless_init(struct ssb_device *dev)
|
|||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_WDS) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->queues = b43_modparam_qos ? 4 : 1;
|
||||
SET_IEEE80211_DEV(hw, dev->dev);
|
||||
if (is_valid_ether_addr(sprom->et1mac))
|
||||
|
|
|
@ -1,489 +0,0 @@
|
|||
/*
|
||||
|
||||
Broadcom B43 wireless driver
|
||||
|
||||
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
|
||||
Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
|
||||
Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
|
||||
Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
|
||||
Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
|
||||
|
||||
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 <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitrev.h>
|
||||
|
||||
#include "b43.h"
|
||||
#include "phy.h"
|
||||
#include "nphy.h"
|
||||
#include "main.h"
|
||||
#include "tables.h"
|
||||
#include "lo.h"
|
||||
#include "wa.h"
|
||||
|
||||
|
||||
static void b43_shm_clear_tssi(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
|
||||
break;
|
||||
case B43_PHYTYPE_B:
|
||||
case B43_PHYTYPE_G:
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
|
||||
b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
|
||||
* This function converts a TSSI value to dBm in Q5.2
|
||||
*/
|
||||
static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
s8 dbm = 0;
|
||||
s32 tmp;
|
||||
|
||||
tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:
|
||||
tmp += 0x80;
|
||||
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 = clamp_val(tmp, 0x00, 0x3F);
|
||||
dbm = phy->tssi2dbm[tmp];
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
|
||||
return dbm;
|
||||
}
|
||||
|
||||
void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
|
||||
int *_bbatt, int *_rfatt)
|
||||
{
|
||||
int rfatt = *_rfatt;
|
||||
int bbatt = *_bbatt;
|
||||
struct b43_txpower_lo_control *lo = dev->phy.lo_control;
|
||||
|
||||
/* Get baseband and radio attenuation values into their permitted ranges.
|
||||
* Radio attenuation affects power level 4 times as much as baseband. */
|
||||
|
||||
/* Range constants */
|
||||
const int rf_min = lo->rfatt_list.min_val;
|
||||
const int rf_max = lo->rfatt_list.max_val;
|
||||
const int bb_min = lo->bbatt_list.min_val;
|
||||
const int bb_max = lo->bbatt_list.max_val;
|
||||
|
||||
while (1) {
|
||||
if (rfatt > rf_max && bbatt > bb_max - 4)
|
||||
break; /* Can not get it into ranges */
|
||||
if (rfatt < rf_min && bbatt < bb_min + 4)
|
||||
break; /* Can not get it into ranges */
|
||||
if (bbatt > bb_max && rfatt > rf_max - 1)
|
||||
break; /* Can not get it into ranges */
|
||||
if (bbatt < bb_min && rfatt < rf_min + 1)
|
||||
break; /* Can not get it into ranges */
|
||||
|
||||
if (bbatt > bb_max) {
|
||||
bbatt -= 4;
|
||||
rfatt += 1;
|
||||
continue;
|
||||
}
|
||||
if (bbatt < bb_min) {
|
||||
bbatt += 4;
|
||||
rfatt -= 1;
|
||||
continue;
|
||||
}
|
||||
if (rfatt > rf_max) {
|
||||
rfatt -= 1;
|
||||
bbatt += 4;
|
||||
continue;
|
||||
}
|
||||
if (rfatt < rf_min) {
|
||||
rfatt += 1;
|
||||
bbatt -= 4;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*_rfatt = clamp_val(rfatt, rf_min, rf_max);
|
||||
*_bbatt = clamp_val(bbatt, bb_min, bb_max);
|
||||
}
|
||||
|
||||
/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
|
||||
void b43_phy_xmitpower(struct b43_wldev *dev)
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
if (phy->cur_idle_tssi == 0)
|
||||
return;
|
||||
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||
(bus->boardinfo.type == SSB_BOARD_BU4306))
|
||||
return;
|
||||
#ifdef CONFIG_B43_DEBUG
|
||||
if (phy->manual_txpower_control)
|
||||
return;
|
||||
#endif
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:{
|
||||
|
||||
//TODO: Nothing for A PHYs yet :-/
|
||||
|
||||
break;
|
||||
}
|
||||
case B43_PHYTYPE_B:
|
||||
case B43_PHYTYPE_G:{
|
||||
u16 tmp;
|
||||
s8 v0, v1, v2, v3;
|
||||
s8 average;
|
||||
int max_pwr;
|
||||
int desired_pwr, estimated_pwr, pwr_adjust;
|
||||
int rfatt_delta, bbatt_delta;
|
||||
int rfatt, bbatt;
|
||||
u8 tx_control;
|
||||
|
||||
tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
|
||||
v0 = (s8) (tmp & 0x00FF);
|
||||
v1 = (s8) ((tmp & 0xFF00) >> 8);
|
||||
tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
|
||||
v2 = (s8) (tmp & 0x00FF);
|
||||
v3 = (s8) ((tmp & 0xFF00) >> 8);
|
||||
tmp = 0;
|
||||
|
||||
if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
|
||||
|| v3 == 0x7F) {
|
||||
tmp =
|
||||
b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
|
||||
v0 = (s8) (tmp & 0x00FF);
|
||||
v1 = (s8) ((tmp & 0xFF00) >> 8);
|
||||
tmp =
|
||||
b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
|
||||
v2 = (s8) (tmp & 0x00FF);
|
||||
v3 = (s8) ((tmp & 0xFF00) >> 8);
|
||||
if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
|
||||
|| v3 == 0x7F)
|
||||
return;
|
||||
v0 = (v0 + 0x20) & 0x3F;
|
||||
v1 = (v1 + 0x20) & 0x3F;
|
||||
v2 = (v2 + 0x20) & 0x3F;
|
||||
v3 = (v3 + 0x20) & 0x3F;
|
||||
tmp = 1;
|
||||
}
|
||||
b43_shm_clear_tssi(dev);
|
||||
|
||||
average = (v0 + v1 + v2 + v3 + 2) / 4;
|
||||
|
||||
if (tmp
|
||||
&& (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
|
||||
0x8))
|
||||
average -= 13;
|
||||
|
||||
estimated_pwr =
|
||||
b43_phy_estimate_power_out(dev, average);
|
||||
|
||||
max_pwr = dev->dev->bus->sprom.maxpwr_bg;
|
||||
if ((dev->dev->bus->sprom.boardflags_lo
|
||||
& B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
|
||||
max_pwr -= 0x3;
|
||||
if (unlikely(max_pwr <= 0)) {
|
||||
b43warn(dev->wl,
|
||||
"Invalid max-TX-power value in SPROM.\n");
|
||||
max_pwr = 60; /* fake it */
|
||||
dev->dev->bus->sprom.maxpwr_bg = max_pwr;
|
||||
}
|
||||
|
||||
/*TODO:
|
||||
max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
|
||||
where REG is the max power as per the regulatory domain
|
||||
*/
|
||||
|
||||
/* 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 = clamp_val(desired_pwr, 0, max_pwr);
|
||||
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
|
||||
b43dbg(dev->wl,
|
||||
"Current TX power output: " Q52_FMT
|
||||
" dBm, " "Desired TX power output: "
|
||||
Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
|
||||
Q52_ARG(desired_pwr));
|
||||
}
|
||||
|
||||
/* Calculate the adjustment delta. */
|
||||
pwr_adjust = desired_pwr - estimated_pwr;
|
||||
|
||||
/* RF attenuation delta. */
|
||||
rfatt_delta = ((pwr_adjust + 7) / 8);
|
||||
/* Lower attenuation => Bigger power output. Negate it. */
|
||||
rfatt_delta = -rfatt_delta;
|
||||
|
||||
/* Baseband attenuation delta. */
|
||||
bbatt_delta = pwr_adjust / 2;
|
||||
/* Lower attenuation => Bigger power output. Negate it. */
|
||||
bbatt_delta = -bbatt_delta;
|
||||
/* RF att affects power level 4 times as much as
|
||||
* Baseband attennuation. Subtract it. */
|
||||
bbatt_delta -= 4 * rfatt_delta;
|
||||
|
||||
/* So do we finally need to adjust something? */
|
||||
if ((rfatt_delta == 0) && (bbatt_delta == 0))
|
||||
return;
|
||||
|
||||
/* Calculate the new attenuation values. */
|
||||
bbatt = phy->bbatt.att;
|
||||
bbatt += bbatt_delta;
|
||||
rfatt = phy->rfatt.att;
|
||||
rfatt += rfatt_delta;
|
||||
|
||||
b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
|
||||
tx_control = phy->tx_control;
|
||||
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
|
||||
if (rfatt <= 1) {
|
||||
if (tx_control == 0) {
|
||||
tx_control =
|
||||
B43_TXCTL_PA2DB |
|
||||
B43_TXCTL_TXMIX;
|
||||
rfatt += 2;
|
||||
bbatt += 2;
|
||||
} else if (dev->dev->bus->sprom.
|
||||
boardflags_lo &
|
||||
B43_BFL_PACTRL) {
|
||||
bbatt += 4 * (rfatt - 2);
|
||||
rfatt = 2;
|
||||
}
|
||||
} else if (rfatt > 4 && tx_control) {
|
||||
tx_control = 0;
|
||||
if (bbatt < 3) {
|
||||
rfatt -= 3;
|
||||
bbatt += 2;
|
||||
} else {
|
||||
rfatt -= 2;
|
||||
bbatt -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Save the control values */
|
||||
phy->tx_control = tx_control;
|
||||
b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
|
||||
phy->rfatt.att = rfatt;
|
||||
phy->bbatt.att = bbatt;
|
||||
|
||||
/* Adjust the hardware */
|
||||
b43_phy_lock(dev);
|
||||
b43_radio_lock(dev);
|
||||
b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
|
||||
phy->tx_control);
|
||||
b43_radio_unlock(dev);
|
||||
b43_phy_unlock(dev);
|
||||
break;
|
||||
}
|
||||
case B43_PHYTYPE_N:
|
||||
b43_nphy_xmitpower(dev);
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
|
||||
{
|
||||
if (num < 0)
|
||||
return num / den;
|
||||
else
|
||||
return (num + den / 2) / den;
|
||||
}
|
||||
|
||||
static inline
|
||||
s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
|
||||
{
|
||||
s32 m1, m2, f = 256, q, delta;
|
||||
s8 i = 0;
|
||||
|
||||
m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
|
||||
m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
|
||||
do {
|
||||
if (i > 15)
|
||||
return -EINVAL;
|
||||
q = b43_tssi2dbm_ad(f * 4096 -
|
||||
b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
|
||||
delta = abs(q - f);
|
||||
f = q;
|
||||
i++;
|
||||
} while (delta >= 2);
|
||||
entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
|
||||
int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
s16 pab0, pab1, pab2;
|
||||
u8 idx;
|
||||
s8 *dyn_tssi2dbm;
|
||||
|
||||
if (phy->type == B43_PHYTYPE_A) {
|
||||
pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
|
||||
pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
|
||||
pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
|
||||
} else {
|
||||
pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
|
||||
pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
|
||||
pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
|
||||
}
|
||||
|
||||
if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
|
||||
phy->tgt_idle_tssi = 0x34;
|
||||
phy->tssi2dbm = b43_tssi2dbm_b_table;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
|
||||
pab0 != -1 && pab1 != -1 && pab2 != -1) {
|
||||
/* The pabX values are set in SPROM. Use them. */
|
||||
if (phy->type == B43_PHYTYPE_A) {
|
||||
if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
|
||||
(s8) dev->dev->bus->sprom.itssi_a != -1)
|
||||
phy->tgt_idle_tssi =
|
||||
(s8) (dev->dev->bus->sprom.itssi_a);
|
||||
else
|
||||
phy->tgt_idle_tssi = 62;
|
||||
} else {
|
||||
if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
|
||||
(s8) dev->dev->bus->sprom.itssi_bg != -1)
|
||||
phy->tgt_idle_tssi =
|
||||
(s8) (dev->dev->bus->sprom.itssi_bg);
|
||||
else
|
||||
phy->tgt_idle_tssi = 62;
|
||||
}
|
||||
dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
|
||||
if (dyn_tssi2dbm == NULL) {
|
||||
b43err(dev->wl, "Could not allocate memory "
|
||||
"for tssi2dbm table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (idx = 0; idx < 64; idx++)
|
||||
if (b43_tssi2dbm_entry
|
||||
(dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
|
||||
phy->tssi2dbm = NULL;
|
||||
b43err(dev->wl, "Could not generate "
|
||||
"tssi2dBm table\n");
|
||||
kfree(dyn_tssi2dbm);
|
||||
return -ENODEV;
|
||||
}
|
||||
phy->tssi2dbm = dyn_tssi2dbm;
|
||||
phy->dyn_tssi_tbl = 1;
|
||||
} else {
|
||||
/* pabX values not set in SPROM. */
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:
|
||||
/* APHY needs a generated table. */
|
||||
phy->tssi2dbm = NULL;
|
||||
b43err(dev->wl, "Could not generate tssi2dBm "
|
||||
"table (wrong SPROM info)!\n");
|
||||
return -ENODEV;
|
||||
case B43_PHYTYPE_B:
|
||||
phy->tgt_idle_tssi = 0x34;
|
||||
phy->tssi2dbm = b43_tssi2dbm_b_table;
|
||||
break;
|
||||
case B43_PHYTYPE_G:
|
||||
phy->tgt_idle_tssi = 0x34;
|
||||
phy->tssi2dbm = b43_tssi2dbm_g_table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void b43_radio_turn_on(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
int err;
|
||||
u8 channel;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (phy->radio_on)
|
||||
return;
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_A:
|
||||
b43_radio_write16(dev, 0x0004, 0x00C0);
|
||||
b43_radio_write16(dev, 0x0005, 0x0008);
|
||||
b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
|
||||
b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
|
||||
b43_radio_init2060(dev);
|
||||
break;
|
||||
case B43_PHYTYPE_B:
|
||||
case B43_PHYTYPE_G:
|
||||
//XXX
|
||||
break;
|
||||
case B43_PHYTYPE_N:
|
||||
b43_nphy_radio_turn_on(dev);
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
phy->radio_on = 1;
|
||||
}
|
||||
|
||||
void b43_radio_turn_off(struct b43_wldev *dev, bool force)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
if (!phy->radio_on && !force)
|
||||
return;
|
||||
|
||||
switch (phy->type) {
|
||||
case B43_PHYTYPE_N:
|
||||
b43_nphy_radio_turn_off(dev);
|
||||
break;
|
||||
case B43_PHYTYPE_A:
|
||||
b43_radio_write16(dev, 0x0004, 0x00FF);
|
||||
b43_radio_write16(dev, 0x0005, 0x00FB);
|
||||
b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
|
||||
b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
|
||||
break;
|
||||
case B43_PHYTYPE_G: {
|
||||
//XXX
|
||||
break;
|
||||
}
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
}
|
||||
phy->radio_on = 0;
|
||||
}
|
|
@ -58,6 +58,25 @@ static inline u16 freq_r3A_value(u16 frequency)
|
|||
return value;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This function converts a TSSI value to dBm in Q5.2 */
|
||||
static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_a *aphy = phy->a;
|
||||
s8 dbm = 0;
|
||||
s32 tmp;
|
||||
|
||||
tmp = (aphy->tgt_idle_tssi - aphy->cur_idle_tssi + tssi);
|
||||
tmp += 0x80;
|
||||
tmp = clamp_val(tmp, 0x00, 0xFF);
|
||||
dbm = aphy->tssi2dbm[tmp];
|
||||
//TODO: There's a FIXME on the specs
|
||||
|
||||
return dbm;
|
||||
}
|
||||
#endif
|
||||
|
||||
void b43_radio_set_tx_iq(struct b43_wldev *dev)
|
||||
{
|
||||
static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
|
||||
|
@ -326,43 +345,106 @@ void b43_phy_inita(struct b43_wldev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Initialise the TSSI->dBm lookup table */
|
||||
static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_a *aphy = phy->a;
|
||||
s16 pab0, pab1, pab2;
|
||||
|
||||
pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
|
||||
pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
|
||||
pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
|
||||
|
||||
if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
|
||||
pab0 != -1 && pab1 != -1 && pab2 != -1) {
|
||||
/* The pabX values are set in SPROM. Use them. */
|
||||
if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
|
||||
(s8) dev->dev->bus->sprom.itssi_a != -1)
|
||||
aphy->tgt_idle_tssi =
|
||||
(s8) (dev->dev->bus->sprom.itssi_a);
|
||||
else
|
||||
aphy->tgt_idle_tssi = 62;
|
||||
aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
|
||||
pab1, pab2);
|
||||
if (!aphy->tssi2dbm)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
/* pabX values not set in SPROM,
|
||||
* but APHY needs a generated table. */
|
||||
aphy->tssi2dbm = NULL;
|
||||
b43err(dev->wl, "Could not generate tssi2dBm "
|
||||
"table (wrong SPROM info)!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b43_aphy_op_allocate(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_a *aphy;
|
||||
int err;
|
||||
|
||||
aphy = kzalloc(sizeof(*aphy), GFP_KERNEL);
|
||||
if (!aphy)
|
||||
return -ENOMEM;
|
||||
dev->phy.a = aphy;
|
||||
|
||||
//TODO init struct b43_phy_a
|
||||
err = b43_aphy_init_tssi2dbm_table(dev);
|
||||
if (err)
|
||||
goto err_free_aphy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_aphy:
|
||||
kfree(aphy);
|
||||
dev->phy.a = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void b43_aphy_op_prepare_structs(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_a *aphy = phy->a;
|
||||
const void *tssi2dbm;
|
||||
int tgt_idle_tssi;
|
||||
|
||||
/* tssi2dbm table is constant, so it is initialized at alloc time.
|
||||
* Save a copy of the pointer. */
|
||||
tssi2dbm = aphy->tssi2dbm;
|
||||
tgt_idle_tssi = aphy->tgt_idle_tssi;
|
||||
|
||||
/* Zero out the whole PHY structure. */
|
||||
memset(aphy, 0, sizeof(*aphy));
|
||||
|
||||
aphy->tssi2dbm = tssi2dbm;
|
||||
aphy->tgt_idle_tssi = tgt_idle_tssi;
|
||||
|
||||
//TODO init struct b43_phy_a
|
||||
|
||||
}
|
||||
|
||||
static void b43_aphy_op_free(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_a *aphy = phy->a;
|
||||
|
||||
kfree(aphy->tssi2dbm);
|
||||
aphy->tssi2dbm = NULL;
|
||||
|
||||
kfree(aphy);
|
||||
dev->phy.a = NULL;
|
||||
}
|
||||
|
||||
static int b43_aphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_a *aphy = dev->phy.a;
|
||||
|
||||
b43_phy_inita(dev);
|
||||
aphy->initialised = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_aphy_op_exit(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_a *aphy = dev->phy.a;
|
||||
|
||||
if (aphy->initialised) {
|
||||
//TODO
|
||||
aphy->initialised = 0;
|
||||
}
|
||||
//TODO
|
||||
kfree(aphy);
|
||||
dev->phy.a = NULL;
|
||||
}
|
||||
|
||||
static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
|
||||
{
|
||||
/* OFDM registers are base-registers for the A-PHY. */
|
||||
|
@ -430,7 +512,23 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
|
|||
|
||||
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
|
||||
enum rfkill_state state)
|
||||
{//TODO
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
||||
if (phy->radio_on)
|
||||
return;
|
||||
b43_radio_write16(dev, 0x0004, 0x00C0);
|
||||
b43_radio_write16(dev, 0x0005, 0x0008);
|
||||
b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
|
||||
b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
|
||||
b43_radio_init2060(dev);
|
||||
} else {
|
||||
b43_radio_write16(dev, 0x0004, 0x00FF);
|
||||
b43_radio_write16(dev, 0x0005, 0x00FB);
|
||||
b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
|
||||
b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
|
||||
}
|
||||
}
|
||||
|
||||
static int b43_aphy_op_switch_channel(struct b43_wldev *dev,
|
||||
|
@ -525,14 +623,16 @@ static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev)
|
|||
|
||||
const struct b43_phy_operations b43_phyops_a = {
|
||||
.allocate = b43_aphy_op_allocate,
|
||||
.free = b43_aphy_op_free,
|
||||
.prepare_structs = b43_aphy_op_prepare_structs,
|
||||
.init = b43_aphy_op_init,
|
||||
.exit = b43_aphy_op_exit,
|
||||
.phy_read = b43_aphy_op_read,
|
||||
.phy_write = b43_aphy_op_write,
|
||||
.radio_read = b43_aphy_op_radio_read,
|
||||
.radio_write = b43_aphy_op_radio_write,
|
||||
.supports_hwpctl = b43_aphy_op_supports_hwpctl,
|
||||
.software_rfkill = b43_aphy_op_software_rfkill,
|
||||
.switch_analog = b43_phyop_switch_analog_generic,
|
||||
.switch_channel = b43_aphy_op_switch_channel,
|
||||
.get_default_chan = b43_aphy_op_get_default_chan,
|
||||
.set_rx_antenna = b43_aphy_op_set_rx_antenna,
|
||||
|
|
|
@ -103,7 +103,13 @@ void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
|
|||
|
||||
|
||||
struct b43_phy_a {
|
||||
bool initialised;
|
||||
/* Pointer to the table used to convert a
|
||||
* TSSI value to dBm-Q5.2 */
|
||||
const s8 *tssi2dbm;
|
||||
/* Target idle TSSI */
|
||||
int tgt_idle_tssi;
|
||||
/* Current idle TSSI */
|
||||
int cur_idle_tssi;//FIXME value currently not set
|
||||
|
||||
/* A-PHY TX Power control value. */
|
||||
u16 txpwr_offset;
|
||||
|
|
|
@ -29,12 +29,13 @@
|
|||
#include "phy_common.h"
|
||||
#include "phy_g.h"
|
||||
#include "phy_a.h"
|
||||
#include "nphy.h"
|
||||
#include "phy_n.h"
|
||||
#include "phy_lp.h"
|
||||
#include "b43.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
int b43_phy_operations_setup(struct b43_wldev *dev)
|
||||
int b43_phy_allocate(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &(dev->phy);
|
||||
int err;
|
||||
|
@ -54,7 +55,9 @@ int b43_phy_operations_setup(struct b43_wldev *dev)
|
|||
#endif
|
||||
break;
|
||||
case B43_PHYTYPE_LP:
|
||||
/* FIXME: Not yet */
|
||||
#ifdef CONFIG_B43_PHY_LP
|
||||
phy->ops = &b43_phyops_lp;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (B43_WARN_ON(!phy->ops))
|
||||
|
@ -67,6 +70,12 @@ int b43_phy_operations_setup(struct b43_wldev *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
void b43_phy_free(struct b43_wldev *dev)
|
||||
{
|
||||
dev->phy.ops->free(dev);
|
||||
dev->phy.ops = NULL;
|
||||
}
|
||||
|
||||
int b43_phy_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
|
@ -365,3 +374,8 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
|
|||
|
||||
return average;
|
||||
}
|
||||
|
||||
void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
|
||||
{
|
||||
b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
|
||||
}
|
||||
|
|
|
@ -74,11 +74,21 @@ enum b43_txpwr_result {
|
|||
/**
|
||||
* struct b43_phy_operations - Function pointers for PHY ops.
|
||||
*
|
||||
* @prepare: Prepare the PHY. This is called before @init.
|
||||
* @allocate: Allocate and initialise the PHY data structures.
|
||||
* Must not be NULL.
|
||||
* @free: Destroy and free the PHY data structures.
|
||||
* Must not be NULL.
|
||||
*
|
||||
* @prepare_structs: Prepare the PHY data structures.
|
||||
* The data structures allocated in @allocate are
|
||||
* initialized here.
|
||||
* Must not be NULL.
|
||||
* @prepare_hardware: Prepare the PHY. This is called before b43_chip_init to
|
||||
* do some early early PHY hardware init.
|
||||
* Can be NULL, if not required.
|
||||
* @init: Initialize the PHY.
|
||||
* Must not be NULL.
|
||||
* @exit: Shutdown the PHY and free all data structures.
|
||||
* @exit: Shutdown the PHY.
|
||||
* Can be NULL, if not required.
|
||||
*
|
||||
* @phy_read: Read from a PHY register.
|
||||
|
@ -98,6 +108,8 @@ enum b43_txpwr_result {
|
|||
* RFKILL_STATE_SOFT_BLOCKED or
|
||||
* RFKILL_STATE_UNBLOCKED
|
||||
* Must not be NULL.
|
||||
* @switch_analog: Turn the Analog on/off.
|
||||
* Must not be NULL.
|
||||
* @switch_channel: Switch the radio to another channel.
|
||||
* Must not be NULL.
|
||||
* @get_default_chan: Just returns the default channel number.
|
||||
|
@ -133,7 +145,9 @@ enum b43_txpwr_result {
|
|||
struct b43_phy_operations {
|
||||
/* Initialisation */
|
||||
int (*allocate)(struct b43_wldev *dev);
|
||||
int (*prepare)(struct b43_wldev *dev);
|
||||
void (*free)(struct b43_wldev *dev);
|
||||
void (*prepare_structs)(struct b43_wldev *dev);
|
||||
int (*prepare_hardware)(struct b43_wldev *dev);
|
||||
int (*init)(struct b43_wldev *dev);
|
||||
void (*exit)(struct b43_wldev *dev);
|
||||
|
||||
|
@ -146,6 +160,7 @@ struct b43_phy_operations {
|
|||
/* Radio */
|
||||
bool (*supports_hwpctl)(struct b43_wldev *dev);
|
||||
void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
|
||||
void (*switch_analog)(struct b43_wldev *dev, bool on);
|
||||
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
|
||||
unsigned int (*get_default_chan)(struct b43_wldev *dev);
|
||||
void (*set_rx_antenna)(struct b43_wldev *dev, int antenna);
|
||||
|
@ -165,6 +180,7 @@ struct b43_phy_operations {
|
|||
struct b43_phy_a;
|
||||
struct b43_phy_g;
|
||||
struct b43_phy_n;
|
||||
struct b43_phy_lp;
|
||||
|
||||
struct b43_phy {
|
||||
/* Hardware operation callbacks. */
|
||||
|
@ -185,6 +201,8 @@ struct b43_phy {
|
|||
struct b43_phy_g *g;
|
||||
/* N-PHY specific information */
|
||||
struct b43_phy_n *n;
|
||||
/* LP-PHY specific information */
|
||||
struct b43_phy_lp *lp;
|
||||
};
|
||||
|
||||
/* Band support flags. */
|
||||
|
@ -234,10 +252,15 @@ struct b43_phy {
|
|||
|
||||
|
||||
/**
|
||||
* b43_phy_operations_setup - Initialize the PHY operations datastructure
|
||||
* based on the current PHY type.
|
||||
* b43_phy_allocate - Allocate PHY structs
|
||||
* Allocate the PHY data structures, based on the current dev->phy.type
|
||||
*/
|
||||
int b43_phy_operations_setup(struct b43_wldev *dev);
|
||||
int b43_phy_allocate(struct b43_wldev *dev);
|
||||
|
||||
/**
|
||||
* b43_phy_free - Free PHY structs
|
||||
*/
|
||||
void b43_phy_free(struct b43_wldev *dev);
|
||||
|
||||
/**
|
||||
* b43_phy_init - Initialise the PHY
|
||||
|
@ -377,5 +400,14 @@ void b43_phy_txpower_adjust_work(struct work_struct *work);
|
|||
*/
|
||||
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset);
|
||||
|
||||
/**
|
||||
* b43_phy_switch_analog_generic - Generic PHY operation for switching the Analog.
|
||||
*
|
||||
* It does the switching based on the PHY0 core register.
|
||||
* Do _not_ call this directly. Only use it as a switch_analog callback
|
||||
* for struct b43_phy_operations.
|
||||
*/
|
||||
void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on);
|
||||
|
||||
|
||||
#endif /* LINUX_B43_PHY_COMMON_H_ */
|
||||
|
|
|
@ -232,11 +232,12 @@ void b43_set_txpower_g(struct b43_wldev *dev,
|
|||
if (unlikely(tx_bias == 0xFF))
|
||||
tx_bias = 0;
|
||||
|
||||
/* Save the values for later */
|
||||
/* Save the values for later. Use memmove, because it's valid
|
||||
* to pass &gphy->rfatt as rfatt pointer argument. Same for bbatt. */
|
||||
gphy->tx_control = tx_control;
|
||||
memcpy(&gphy->rfatt, rfatt, sizeof(*rfatt));
|
||||
memmove(&gphy->rfatt, rfatt, sizeof(*rfatt));
|
||||
gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
|
||||
memcpy(&gphy->bbatt, bbatt, sizeof(*bbatt));
|
||||
memmove(&gphy->bbatt, bbatt, sizeof(*bbatt));
|
||||
|
||||
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
|
||||
b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
|
||||
|
@ -2634,7 +2635,7 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev)
|
|||
{
|
||||
struct b43_phy_g *gphy;
|
||||
struct b43_txpower_lo_control *lo;
|
||||
int err, i;
|
||||
int err;
|
||||
|
||||
gphy = kzalloc(sizeof(*gphy), GFP_KERNEL);
|
||||
if (!gphy) {
|
||||
|
@ -2643,6 +2644,51 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev)
|
|||
}
|
||||
dev->phy.g = gphy;
|
||||
|
||||
lo = kzalloc(sizeof(*lo), GFP_KERNEL);
|
||||
if (!lo) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_gphy;
|
||||
}
|
||||
gphy->lo_control = lo;
|
||||
|
||||
err = b43_gphy_init_tssi2dbm_table(dev);
|
||||
if (err)
|
||||
goto err_free_lo;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_lo:
|
||||
kfree(lo);
|
||||
err_free_gphy:
|
||||
kfree(gphy);
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void b43_gphy_op_prepare_structs(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_g *gphy = phy->g;
|
||||
const void *tssi2dbm;
|
||||
int tgt_idle_tssi;
|
||||
struct b43_txpower_lo_control *lo;
|
||||
unsigned int i;
|
||||
|
||||
/* tssi2dbm table is constant, so it is initialized at alloc time.
|
||||
* Save a copy of the pointer. */
|
||||
tssi2dbm = gphy->tssi2dbm;
|
||||
tgt_idle_tssi = gphy->tgt_idle_tssi;
|
||||
/* Save the LO pointer. */
|
||||
lo = gphy->lo_control;
|
||||
|
||||
/* Zero out the whole PHY structure. */
|
||||
memset(gphy, 0, sizeof(*gphy));
|
||||
|
||||
/* Restore pointers. */
|
||||
gphy->tssi2dbm = tssi2dbm;
|
||||
gphy->tgt_idle_tssi = tgt_idle_tssi;
|
||||
gphy->lo_control = lo;
|
||||
|
||||
memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig));
|
||||
|
||||
/* NRSSI */
|
||||
|
@ -2661,31 +2707,28 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev)
|
|||
|
||||
gphy->average_tssi = 0xFF;
|
||||
|
||||
lo = kzalloc(sizeof(*lo), GFP_KERNEL);
|
||||
if (!lo) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_gphy;
|
||||
}
|
||||
gphy->lo_control = lo;
|
||||
|
||||
/* Local Osciallator structure */
|
||||
lo->tx_bias = 0xFF;
|
||||
INIT_LIST_HEAD(&lo->calib_list);
|
||||
|
||||
err = b43_gphy_init_tssi2dbm_table(dev);
|
||||
if (err)
|
||||
goto err_free_lo;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_lo:
|
||||
kfree(lo);
|
||||
err_free_gphy:
|
||||
kfree(gphy);
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int b43_gphy_op_prepare(struct b43_wldev *dev)
|
||||
static void b43_gphy_op_free(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_g *gphy = phy->g;
|
||||
|
||||
kfree(gphy->lo_control);
|
||||
|
||||
if (gphy->dyn_tssi_tbl)
|
||||
kfree(gphy->tssi2dbm);
|
||||
gphy->dyn_tssi_tbl = 0;
|
||||
gphy->tssi2dbm = NULL;
|
||||
|
||||
kfree(gphy);
|
||||
dev->phy.g = NULL;
|
||||
}
|
||||
|
||||
static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_g *gphy = phy->g;
|
||||
|
@ -2717,28 +2760,14 @@ static int b43_gphy_op_prepare(struct b43_wldev *dev)
|
|||
|
||||
static int b43_gphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_g *gphy = dev->phy.g;
|
||||
|
||||
b43_phy_initg(dev);
|
||||
gphy->initialised = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_gphy_op_exit(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_g *gphy = dev->phy.g;
|
||||
|
||||
if (gphy->initialised) {
|
||||
//TODO
|
||||
gphy->initialised = 0;
|
||||
}
|
||||
b43_lo_g_cleanup(dev);
|
||||
kfree(gphy->lo_control);
|
||||
if (gphy->dyn_tssi_tbl)
|
||||
kfree(gphy->tssi2dbm);
|
||||
kfree(gphy);
|
||||
dev->phy.g = NULL;
|
||||
}
|
||||
|
||||
static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
|
||||
|
@ -3231,7 +3260,9 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
|
|||
|
||||
const struct b43_phy_operations b43_phyops_g = {
|
||||
.allocate = b43_gphy_op_allocate,
|
||||
.prepare = b43_gphy_op_prepare,
|
||||
.free = b43_gphy_op_free,
|
||||
.prepare_structs = b43_gphy_op_prepare_structs,
|
||||
.prepare_hardware = b43_gphy_op_prepare_hardware,
|
||||
.init = b43_gphy_op_init,
|
||||
.exit = b43_gphy_op_exit,
|
||||
.phy_read = b43_gphy_op_read,
|
||||
|
@ -3240,6 +3271,7 @@ const struct b43_phy_operations b43_phyops_g = {
|
|||
.radio_write = b43_gphy_op_radio_write,
|
||||
.supports_hwpctl = b43_gphy_op_supports_hwpctl,
|
||||
.software_rfkill = b43_gphy_op_software_rfkill,
|
||||
.switch_analog = b43_phyop_switch_analog_generic,
|
||||
.switch_channel = b43_gphy_op_switch_channel,
|
||||
.get_default_chan = b43_gphy_op_get_default_chan,
|
||||
.set_rx_antenna = b43_gphy_op_set_rx_antenna,
|
||||
|
|
|
@ -114,8 +114,6 @@ static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
|
|||
struct b43_txpower_lo_control;
|
||||
|
||||
struct b43_phy_g {
|
||||
bool initialised;
|
||||
|
||||
/* ACI (adjacent channel interference) flags. */
|
||||
bool aci_enable;
|
||||
bool aci_wlan_automatic;
|
||||
|
@ -202,6 +200,8 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
|
|||
void b43_gphy_channel_switch(struct b43_wldev *dev,
|
||||
unsigned int channel,
|
||||
bool synthetic_pu_workaround);
|
||||
u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
|
||||
s16 pab0, s16 pab1, s16 pab2);
|
||||
|
||||
struct b43_phy_operations;
|
||||
extern const struct b43_phy_operations b43_phyops_g;
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
|
||||
Broadcom B43 wireless driver
|
||||
IEEE 802.11g LP-PHY driver
|
||||
|
||||
Copyright (c) 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 "phy_lp.h"
|
||||
#include "phy_common.h"
|
||||
|
||||
|
||||
static int b43_lpphy_op_allocate(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy;
|
||||
|
||||
lpphy = kzalloc(sizeof(*lpphy), GFP_KERNEL);
|
||||
if (!lpphy)
|
||||
return -ENOMEM;
|
||||
dev->phy.lp = lpphy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_prepare_structs(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_lp *lpphy = phy->lp;
|
||||
|
||||
memset(lpphy, 0, sizeof(*lpphy));
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_free(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_lp *lpphy = dev->phy.lp;
|
||||
|
||||
kfree(lpphy);
|
||||
dev->phy.lp = NULL;
|
||||
}
|
||||
|
||||
static int b43_lpphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
//TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
|
||||
{
|
||||
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
|
||||
return b43_read16(dev, B43_MMIO_PHY_DATA);
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
|
||||
{
|
||||
b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
|
||||
b43_write16(dev, B43_MMIO_PHY_DATA, value);
|
||||
}
|
||||
|
||||
static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
|
||||
{
|
||||
/* Register 1 is a 32-bit register. */
|
||||
B43_WARN_ON(reg == 1);
|
||||
/* LP-PHY needs a special bit set for read access */
|
||||
if (dev->phy.rev < 2) {
|
||||
if (reg != 0x4001)
|
||||
reg |= 0x100;
|
||||
} else
|
||||
reg |= 0x200;
|
||||
|
||||
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
|
||||
return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
|
||||
{
|
||||
/* Register 1 is a 32-bit register. */
|
||||
B43_WARN_ON(reg == 1);
|
||||
|
||||
b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
|
||||
b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
|
||||
enum rfkill_state state)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
static int b43_lpphy_op_switch_channel(struct b43_wldev *dev,
|
||||
unsigned int new_channel)
|
||||
{
|
||||
//TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int b43_lpphy_op_get_default_chan(struct b43_wldev *dev)
|
||||
{
|
||||
return 1; /* Default to channel 1 */
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
static void b43_lpphy_op_adjust_txpower(struct b43_wldev *dev)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
|
||||
bool ignore_tssi)
|
||||
{
|
||||
//TODO
|
||||
return B43_TXPWR_RES_DONE;
|
||||
}
|
||||
|
||||
|
||||
const struct b43_phy_operations b43_phyops_lp = {
|
||||
.allocate = b43_lpphy_op_allocate,
|
||||
.free = b43_lpphy_op_free,
|
||||
.prepare_structs = b43_lpphy_op_prepare_structs,
|
||||
.init = b43_lpphy_op_init,
|
||||
.phy_read = b43_lpphy_op_read,
|
||||
.phy_write = b43_lpphy_op_write,
|
||||
.radio_read = b43_lpphy_op_radio_read,
|
||||
.radio_write = b43_lpphy_op_radio_write,
|
||||
.software_rfkill = b43_lpphy_op_software_rfkill,
|
||||
.switch_analog = b43_phyop_switch_analog_generic,
|
||||
.switch_channel = b43_lpphy_op_switch_channel,
|
||||
.get_default_chan = b43_lpphy_op_get_default_chan,
|
||||
.set_rx_antenna = b43_lpphy_op_set_rx_antenna,
|
||||
.recalc_txpower = b43_lpphy_op_recalc_txpower,
|
||||
.adjust_txpower = b43_lpphy_op_adjust_txpower,
|
||||
};
|
|
@ -0,0 +1,540 @@
|
|||
#ifndef LINUX_B43_PHY_LP_H_
|
||||
#define LINUX_B43_PHY_LP_H_
|
||||
|
||||
/* Definitions for the LP-PHY */
|
||||
|
||||
|
||||
|
||||
|
||||
#define B43_LP_RADIO(radio_reg) (radio_reg)
|
||||
#define B43_LP_NORTH(radio_reg) B43_LP_RADIO(radio_reg)
|
||||
#define B43_LP_SOUTH(radio_reg) B43_LP_RADIO((radio_reg) | 0x4000)
|
||||
|
||||
|
||||
/*** Broadcom 2062 NORTH radio registers ***/
|
||||
#define B2062_N_COMM1 B43_LP_NORTH(0x000) /* Common 01 (north) */
|
||||
#define B2062_N_COMM2 B43_LP_NORTH(0x002) /* Common 02 (north) */
|
||||
#define B2062_N_COMM3 B43_LP_NORTH(0x003) /* Common 03 (north) */
|
||||
#define B2062_N_COMM4 B43_LP_NORTH(0x004) /* Common 04 (north) */
|
||||
#define B2062_N_COMM5 B43_LP_NORTH(0x005) /* Common 05 (north) */
|
||||
#define B2062_N_COMM6 B43_LP_NORTH(0x006) /* Common 06 (north) */
|
||||
#define B2062_N_COMM7 B43_LP_NORTH(0x007) /* Common 07 (north) */
|
||||
#define B2062_N_COMM8 B43_LP_NORTH(0x008) /* Common 08 (north) */
|
||||
#define B2062_N_COMM9 B43_LP_NORTH(0x009) /* Common 09 (north) */
|
||||
#define B2062_N_COMM10 B43_LP_NORTH(0x00A) /* Common 10 (north) */
|
||||
#define B2062_N_COMM11 B43_LP_NORTH(0x00B) /* Common 11 (north) */
|
||||
#define B2062_N_COMM12 B43_LP_NORTH(0x00C) /* Common 12 (north) */
|
||||
#define B2062_N_COMM13 B43_LP_NORTH(0x00D) /* Common 13 (north) */
|
||||
#define B2062_N_COMM14 B43_LP_NORTH(0x00E) /* Common 14 (north) */
|
||||
#define B2062_N_COMM15 B43_LP_NORTH(0x00F) /* Common 15 (north) */
|
||||
#define B2062_N_PDN_CTL0 B43_LP_NORTH(0x010) /* PDN Control 0 (north) */
|
||||
#define B2062_N_PDN_CTL1 B43_LP_NORTH(0x011) /* PDN Control 1 (north) */
|
||||
#define B2062_N_PDN_CTL2 B43_LP_NORTH(0x012) /* PDN Control 2 (north) */
|
||||
#define B2062_N_PDN_CTL3 B43_LP_NORTH(0x013) /* PDN Control 3 (north) */
|
||||
#define B2062_N_PDN_CTL4 B43_LP_NORTH(0x014) /* PDN Control 4 (north) */
|
||||
#define B2062_N_GEN_CTL0 B43_LP_NORTH(0x015) /* GEN Control 0 (north) */
|
||||
#define B2062_N_IQ_CALIB B43_LP_NORTH(0x016) /* IQ Calibration (north) */
|
||||
#define B2062_N_LGENC B43_LP_NORTH(0x017) /* LGENC (north) */
|
||||
#define B2062_N_LGENA_LPF B43_LP_NORTH(0x018) /* LGENA LPF (north) */
|
||||
#define B2062_N_LGENA_BIAS0 B43_LP_NORTH(0x019) /* LGENA Bias 0 (north) */
|
||||
#define B2062_N_LGNEA_BIAS1 B43_LP_NORTH(0x01A) /* LGNEA Bias 1 (north) */
|
||||
#define B2062_N_LGENA_CTL0 B43_LP_NORTH(0x01B) /* LGENA Control 0 (north) */
|
||||
#define B2062_N_LGENA_CTL1 B43_LP_NORTH(0x01C) /* LGENA Control 1 (north) */
|
||||
#define B2062_N_LGENA_CTL2 B43_LP_NORTH(0x01D) /* LGENA Control 2 (north) */
|
||||
#define B2062_N_LGENA_TUNE0 B43_LP_NORTH(0x01E) /* LGENA Tune 0 (north) */
|
||||
#define B2062_N_LGENA_TUNE1 B43_LP_NORTH(0x01F) /* LGENA Tune 1 (north) */
|
||||
#define B2062_N_LGENA_TUNE2 B43_LP_NORTH(0x020) /* LGENA Tune 2 (north) */
|
||||
#define B2062_N_LGENA_TUNE3 B43_LP_NORTH(0x021) /* LGENA Tune 3 (north) */
|
||||
#define B2062_N_LGENA_CTL3 B43_LP_NORTH(0x022) /* LGENA Control 3 (north) */
|
||||
#define B2062_N_LGENA_CTL4 B43_LP_NORTH(0x023) /* LGENA Control 4 (north) */
|
||||
#define B2062_N_LGENA_CTL5 B43_LP_NORTH(0x024) /* LGENA Control 5 (north) */
|
||||
#define B2062_N_LGENA_CTL6 B43_LP_NORTH(0x025) /* LGENA Control 6 (north) */
|
||||
#define B2062_N_LGENA_CTL7 B43_LP_NORTH(0x026) /* LGENA Control 7 (north) */
|
||||
#define B2062_N_RXA_CTL0 B43_LP_NORTH(0x027) /* RXA Control 0 (north) */
|
||||
#define B2062_N_RXA_CTL1 B43_LP_NORTH(0x028) /* RXA Control 1 (north) */
|
||||
#define B2062_N_RXA_CTL2 B43_LP_NORTH(0x029) /* RXA Control 2 (north) */
|
||||
#define B2062_N_RXA_CTL3 B43_LP_NORTH(0x02A) /* RXA Control 3 (north) */
|
||||
#define B2062_N_RXA_CTL4 B43_LP_NORTH(0x02B) /* RXA Control 4 (north) */
|
||||
#define B2062_N_RXA_CTL5 B43_LP_NORTH(0x02C) /* RXA Control 5 (north) */
|
||||
#define B2062_N_RXA_CTL6 B43_LP_NORTH(0x02D) /* RXA Control 6 (north) */
|
||||
#define B2062_N_RXA_CTL7 B43_LP_NORTH(0x02E) /* RXA Control 7 (north) */
|
||||
#define B2062_N_RXBB_CTL0 B43_LP_NORTH(0x02F) /* RXBB Control 0 (north) */
|
||||
#define B2062_N_RXBB_CTL1 B43_LP_NORTH(0x030) /* RXBB Control 1 (north) */
|
||||
#define B2062_N_RXBB_CTL2 B43_LP_NORTH(0x031) /* RXBB Control 2 (north) */
|
||||
#define B2062_N_RXBB_GAIN0 B43_LP_NORTH(0x032) /* RXBB Gain 0 (north) */
|
||||
#define B2062_N_RXBB_GAIN1 B43_LP_NORTH(0x033) /* RXBB Gain 1 (north) */
|
||||
#define B2062_N_RXBB_GAIN2 B43_LP_NORTH(0x034) /* RXBB Gain 2 (north) */
|
||||
#define B2062_N_RXBB_GAIN3 B43_LP_NORTH(0x035) /* RXBB Gain 3 (north) */
|
||||
#define B2062_N_RXBB_RSSI0 B43_LP_NORTH(0x036) /* RXBB RSSI 0 (north) */
|
||||
#define B2062_N_RXBB_RSSI1 B43_LP_NORTH(0x037) /* RXBB RSSI 1 (north) */
|
||||
#define B2062_N_RXBB_CALIB0 B43_LP_NORTH(0x038) /* RXBB Calibration0 (north) */
|
||||
#define B2062_N_RXBB_CALIB1 B43_LP_NORTH(0x039) /* RXBB Calibration1 (north) */
|
||||
#define B2062_N_RXBB_CALIB2 B43_LP_NORTH(0x03A) /* RXBB Calibration2 (north) */
|
||||
#define B2062_N_RXBB_BIAS0 B43_LP_NORTH(0x03B) /* RXBB Bias 0 (north) */
|
||||
#define B2062_N_RXBB_BIAS1 B43_LP_NORTH(0x03C) /* RXBB Bias 1 (north) */
|
||||
#define B2062_N_RXBB_BIAS2 B43_LP_NORTH(0x03D) /* RXBB Bias 2 (north) */
|
||||
#define B2062_N_RXBB_BIAS3 B43_LP_NORTH(0x03E) /* RXBB Bias 3 (north) */
|
||||
#define B2062_N_RXBB_BIAS4 B43_LP_NORTH(0x03F) /* RXBB Bias 4 (north) */
|
||||
#define B2062_N_RXBB_BIAS5 B43_LP_NORTH(0x040) /* RXBB Bias 5 (north) */
|
||||
#define B2062_N_RXBB_RSSI2 B43_LP_NORTH(0x041) /* RXBB RSSI 2 (north) */
|
||||
#define B2062_N_RXBB_RSSI3 B43_LP_NORTH(0x042) /* RXBB RSSI 3 (north) */
|
||||
#define B2062_N_RXBB_RSSI4 B43_LP_NORTH(0x043) /* RXBB RSSI 4 (north) */
|
||||
#define B2062_N_RXBB_RSSI5 B43_LP_NORTH(0x044) /* RXBB RSSI 5 (north) */
|
||||
#define B2062_N_TX_CTL0 B43_LP_NORTH(0x045) /* TX Control 0 (north) */
|
||||
#define B2062_N_TX_CTL1 B43_LP_NORTH(0x046) /* TX Control 1 (north) */
|
||||
#define B2062_N_TX_CTL2 B43_LP_NORTH(0x047) /* TX Control 2 (north) */
|
||||
#define B2062_N_TX_CTL3 B43_LP_NORTH(0x048) /* TX Control 3 (north) */
|
||||
#define B2062_N_TX_CTL4 B43_LP_NORTH(0x049) /* TX Control 4 (north) */
|
||||
#define B2062_N_TX_CTL5 B43_LP_NORTH(0x04A) /* TX Control 5 (north) */
|
||||
#define B2062_N_TX_CTL6 B43_LP_NORTH(0x04B) /* TX Control 6 (north) */
|
||||
#define B2062_N_TX_CTL7 B43_LP_NORTH(0x04C) /* TX Control 7 (north) */
|
||||
#define B2062_N_TX_CTL8 B43_LP_NORTH(0x04D) /* TX Control 8 (north) */
|
||||
#define B2062_N_TX_CTL9 B43_LP_NORTH(0x04E) /* TX Control 9 (north) */
|
||||
#define B2062_N_TX_CTL_A B43_LP_NORTH(0x04F) /* TX Control A (north) */
|
||||
#define B2062_N_TX_GC2G B43_LP_NORTH(0x050) /* TX GC2G (north) */
|
||||
#define B2062_N_TX_GC5G B43_LP_NORTH(0x051) /* TX GC5G (north) */
|
||||
#define B2062_N_TX_TUNE B43_LP_NORTH(0x052) /* TX Tune (north) */
|
||||
#define B2062_N_TX_PAD B43_LP_NORTH(0x053) /* TX PAD (north) */
|
||||
#define B2062_N_TX_PGA B43_LP_NORTH(0x054) /* TX PGA (north) */
|
||||
#define B2062_N_TX_PADAUX B43_LP_NORTH(0x055) /* TX PADAUX (north) */
|
||||
#define B2062_N_TX_PGAAUX B43_LP_NORTH(0x056) /* TX PGAAUX (north) */
|
||||
#define B2062_N_TSSI_CTL0 B43_LP_NORTH(0x057) /* TSSI Control 0 (north) */
|
||||
#define B2062_N_TSSI_CTL1 B43_LP_NORTH(0x058) /* TSSI Control 1 (north) */
|
||||
#define B2062_N_TSSI_CTL2 B43_LP_NORTH(0x059) /* TSSI Control 2 (north) */
|
||||
#define B2062_N_IQ_CALIB_CTL0 B43_LP_NORTH(0x05A) /* IQ Calibration Control 0 (north) */
|
||||
#define B2062_N_IQ_CALIB_CTL1 B43_LP_NORTH(0x05B) /* IQ Calibration Control 1 (north) */
|
||||
#define B2062_N_IQ_CALIB_CTL2 B43_LP_NORTH(0x05C) /* IQ Calibration Control 2 (north) */
|
||||
#define B2062_N_CALIB_TS B43_LP_NORTH(0x05D) /* Calibration TS (north) */
|
||||
#define B2062_N_CALIB_CTL0 B43_LP_NORTH(0x05E) /* Calibration Control 0 (north) */
|
||||
#define B2062_N_CALIB_CTL1 B43_LP_NORTH(0x05F) /* Calibration Control 1 (north) */
|
||||
#define B2062_N_CALIB_CTL2 B43_LP_NORTH(0x060) /* Calibration Control 2 (north) */
|
||||
#define B2062_N_CALIB_CTL3 B43_LP_NORTH(0x061) /* Calibration Control 3 (north) */
|
||||
#define B2062_N_CALIB_CTL4 B43_LP_NORTH(0x062) /* Calibration Control 4 (north) */
|
||||
#define B2062_N_CALIB_DBG0 B43_LP_NORTH(0x063) /* Calibration Debug 0 (north) */
|
||||
#define B2062_N_CALIB_DBG1 B43_LP_NORTH(0x064) /* Calibration Debug 1 (north) */
|
||||
#define B2062_N_CALIB_DBG2 B43_LP_NORTH(0x065) /* Calibration Debug 2 (north) */
|
||||
#define B2062_N_CALIB_DBG3 B43_LP_NORTH(0x066) /* Calibration Debug 3 (north) */
|
||||
#define B2062_N_PSENSE_CTL0 B43_LP_NORTH(0x069) /* PSENSE Control 0 (north) */
|
||||
#define B2062_N_PSENSE_CTL1 B43_LP_NORTH(0x06A) /* PSENSE Control 1 (north) */
|
||||
#define B2062_N_PSENSE_CTL2 B43_LP_NORTH(0x06B) /* PSENSE Control 2 (north) */
|
||||
#define B2062_N_TEST_BUF0 B43_LP_NORTH(0x06C) /* TEST BUF0 (north) */
|
||||
|
||||
/*** Broadcom 2062 SOUTH radio registers ***/
|
||||
#define B2062_S_COMM1 B43_LP_SOUTH(0x000) /* Common 01 (south) */
|
||||
#define B2062_S_RADIO_ID_CODE B43_LP_SOUTH(0x001) /* Radio ID code (south) */
|
||||
#define B2062_S_COMM2 B43_LP_SOUTH(0x002) /* Common 02 (south) */
|
||||
#define B2062_S_COMM3 B43_LP_SOUTH(0x003) /* Common 03 (south) */
|
||||
#define B2062_S_COMM4 B43_LP_SOUTH(0x004) /* Common 04 (south) */
|
||||
#define B2062_S_COMM5 B43_LP_SOUTH(0x005) /* Common 05 (south) */
|
||||
#define B2062_S_COMM6 B43_LP_SOUTH(0x006) /* Common 06 (south) */
|
||||
#define B2062_S_COMM7 B43_LP_SOUTH(0x007) /* Common 07 (south) */
|
||||
#define B2062_S_COMM8 B43_LP_SOUTH(0x008) /* Common 08 (south) */
|
||||
#define B2062_S_COMM9 B43_LP_SOUTH(0x009) /* Common 09 (south) */
|
||||
#define B2062_S_COMM10 B43_LP_SOUTH(0x00A) /* Common 10 (south) */
|
||||
#define B2062_S_COMM11 B43_LP_SOUTH(0x00B) /* Common 11 (south) */
|
||||
#define B2062_S_COMM12 B43_LP_SOUTH(0x00C) /* Common 12 (south) */
|
||||
#define B2062_S_COMM13 B43_LP_SOUTH(0x00D) /* Common 13 (south) */
|
||||
#define B2062_S_COMM14 B43_LP_SOUTH(0x00E) /* Common 14 (south) */
|
||||
#define B2062_S_COMM15 B43_LP_SOUTH(0x00F) /* Common 15 (south) */
|
||||
#define B2062_S_PDS_CTL0 B43_LP_SOUTH(0x010) /* PDS Control 0 (south) */
|
||||
#define B2062_S_PDS_CTL1 B43_LP_SOUTH(0x011) /* PDS Control 1 (south) */
|
||||
#define B2062_S_PDS_CTL2 B43_LP_SOUTH(0x012) /* PDS Control 2 (south) */
|
||||
#define B2062_S_PDS_CTL3 B43_LP_SOUTH(0x013) /* PDS Control 3 (south) */
|
||||
#define B2062_S_BG_CTL0 B43_LP_SOUTH(0x014) /* BG Control 0 (south) */
|
||||
#define B2062_S_BG_CTL1 B43_LP_SOUTH(0x015) /* BG Control 1 (south) */
|
||||
#define B2062_S_BG_CTL2 B43_LP_SOUTH(0x016) /* BG Control 2 (south) */
|
||||
#define B2062_S_LGENG_CTL0 B43_LP_SOUTH(0x017) /* LGENG Control 00 (south) */
|
||||
#define B2062_S_LGENG_CTL1 B43_LP_SOUTH(0x018) /* LGENG Control 01 (south) */
|
||||
#define B2062_S_LGENG_CTL2 B43_LP_SOUTH(0x019) /* LGENG Control 02 (south) */
|
||||
#define B2062_S_LGENG_CTL3 B43_LP_SOUTH(0x01A) /* LGENG Control 03 (south) */
|
||||
#define B2062_S_LGENG_CTL4 B43_LP_SOUTH(0x01B) /* LGENG Control 04 (south) */
|
||||
#define B2062_S_LGENG_CTL5 B43_LP_SOUTH(0x01C) /* LGENG Control 05 (south) */
|
||||
#define B2062_S_LGENG_CTL6 B43_LP_SOUTH(0x01D) /* LGENG Control 06 (south) */
|
||||
#define B2062_S_LGENG_CTL7 B43_LP_SOUTH(0x01E) /* LGENG Control 07 (south) */
|
||||
#define B2062_S_LGENG_CTL8 B43_LP_SOUTH(0x01F) /* LGENG Control 08 (south) */
|
||||
#define B2062_S_LGENG_CTL9 B43_LP_SOUTH(0x020) /* LGENG Control 09 (south) */
|
||||
#define B2062_S_LGENG_CTL10 B43_LP_SOUTH(0x021) /* LGENG Control 10 (south) */
|
||||
#define B2062_S_LGENG_CTL11 B43_LP_SOUTH(0x022) /* LGENG Control 11 (south) */
|
||||
#define B2062_S_REFPLL_CTL0 B43_LP_SOUTH(0x023) /* REFPLL Control 00 (south) */
|
||||
#define B2062_S_REFPLL_CTL1 B43_LP_SOUTH(0x024) /* REFPLL Control 01 (south) */
|
||||
#define B2062_S_REFPLL_CTL2 B43_LP_SOUTH(0x025) /* REFPLL Control 02 (south) */
|
||||
#define B2062_S_REFPLL_CTL3 B43_LP_SOUTH(0x026) /* REFPLL Control 03 (south) */
|
||||
#define B2062_S_REFPLL_CTL4 B43_LP_SOUTH(0x027) /* REFPLL Control 04 (south) */
|
||||
#define B2062_S_REFPLL_CTL5 B43_LP_SOUTH(0x028) /* REFPLL Control 05 (south) */
|
||||
#define B2062_S_REFPLL_CTL6 B43_LP_SOUTH(0x029) /* REFPLL Control 06 (south) */
|
||||
#define B2062_S_REFPLL_CTL7 B43_LP_SOUTH(0x02A) /* REFPLL Control 07 (south) */
|
||||
#define B2062_S_REFPLL_CTL8 B43_LP_SOUTH(0x02B) /* REFPLL Control 08 (south) */
|
||||
#define B2062_S_REFPLL_CTL9 B43_LP_SOUTH(0x02C) /* REFPLL Control 09 (south) */
|
||||
#define B2062_S_REFPLL_CTL10 B43_LP_SOUTH(0x02D) /* REFPLL Control 10 (south) */
|
||||
#define B2062_S_REFPLL_CTL11 B43_LP_SOUTH(0x02E) /* REFPLL Control 11 (south) */
|
||||
#define B2062_S_REFPLL_CTL12 B43_LP_SOUTH(0x02F) /* REFPLL Control 12 (south) */
|
||||
#define B2062_S_REFPLL_CTL13 B43_LP_SOUTH(0x030) /* REFPLL Control 13 (south) */
|
||||
#define B2062_S_REFPLL_CTL14 B43_LP_SOUTH(0x031) /* REFPLL Control 14 (south) */
|
||||
#define B2062_S_REFPLL_CTL15 B43_LP_SOUTH(0x032) /* REFPLL Control 15 (south) */
|
||||
#define B2062_S_REFPLL_CTL16 B43_LP_SOUTH(0x033) /* REFPLL Control 16 (south) */
|
||||
#define B2062_S_RFPLL_CTL0 B43_LP_SOUTH(0x034) /* RFPLL Control 00 (south) */
|
||||
#define B2062_S_RFPLL_CTL1 B43_LP_SOUTH(0x035) /* RFPLL Control 01 (south) */
|
||||
#define B2062_S_RFPLL_CTL2 B43_LP_SOUTH(0x036) /* RFPLL Control 02 (south) */
|
||||
#define B2062_S_RFPLL_CTL3 B43_LP_SOUTH(0x037) /* RFPLL Control 03 (south) */
|
||||
#define B2062_S_RFPLL_CTL4 B43_LP_SOUTH(0x038) /* RFPLL Control 04 (south) */
|
||||
#define B2062_S_RFPLL_CTL5 B43_LP_SOUTH(0x039) /* RFPLL Control 05 (south) */
|
||||
#define B2062_S_RFPLL_CTL6 B43_LP_SOUTH(0x03A) /* RFPLL Control 06 (south) */
|
||||
#define B2062_S_RFPLL_CTL7 B43_LP_SOUTH(0x03B) /* RFPLL Control 07 (south) */
|
||||
#define B2062_S_RFPLL_CTL8 B43_LP_SOUTH(0x03C) /* RFPLL Control 08 (south) */
|
||||
#define B2062_S_RFPLL_CTL9 B43_LP_SOUTH(0x03D) /* RFPLL Control 09 (south) */
|
||||
#define B2062_S_RFPLL_CTL10 B43_LP_SOUTH(0x03E) /* RFPLL Control 10 (south) */
|
||||
#define B2062_S_RFPLL_CTL11 B43_LP_SOUTH(0x03F) /* RFPLL Control 11 (south) */
|
||||
#define B2062_S_RFPLL_CTL12 B43_LP_SOUTH(0x040) /* RFPLL Control 12 (south) */
|
||||
#define B2062_S_RFPLL_CTL13 B43_LP_SOUTH(0x041) /* RFPLL Control 13 (south) */
|
||||
#define B2062_S_RFPLL_CTL14 B43_LP_SOUTH(0x042) /* RFPLL Control 14 (south) */
|
||||
#define B2062_S_RFPLL_CTL15 B43_LP_SOUTH(0x043) /* RFPLL Control 15 (south) */
|
||||
#define B2062_S_RFPLL_CTL16 B43_LP_SOUTH(0x044) /* RFPLL Control 16 (south) */
|
||||
#define B2062_S_RFPLL_CTL17 B43_LP_SOUTH(0x045) /* RFPLL Control 17 (south) */
|
||||
#define B2062_S_RFPLL_CTL18 B43_LP_SOUTH(0x046) /* RFPLL Control 18 (south) */
|
||||
#define B2062_S_RFPLL_CTL19 B43_LP_SOUTH(0x047) /* RFPLL Control 19 (south) */
|
||||
#define B2062_S_RFPLL_CTL20 B43_LP_SOUTH(0x048) /* RFPLL Control 20 (south) */
|
||||
#define B2062_S_RFPLL_CTL21 B43_LP_SOUTH(0x049) /* RFPLL Control 21 (south) */
|
||||
#define B2062_S_RFPLL_CTL22 B43_LP_SOUTH(0x04A) /* RFPLL Control 22 (south) */
|
||||
#define B2062_S_RFPLL_CTL23 B43_LP_SOUTH(0x04B) /* RFPLL Control 23 (south) */
|
||||
#define B2062_S_RFPLL_CTL24 B43_LP_SOUTH(0x04C) /* RFPLL Control 24 (south) */
|
||||
#define B2062_S_RFPLL_CTL25 B43_LP_SOUTH(0x04D) /* RFPLL Control 25 (south) */
|
||||
#define B2062_S_RFPLL_CTL26 B43_LP_SOUTH(0x04E) /* RFPLL Control 26 (south) */
|
||||
#define B2062_S_RFPLL_CTL27 B43_LP_SOUTH(0x04F) /* RFPLL Control 27 (south) */
|
||||
#define B2062_S_RFPLL_CTL28 B43_LP_SOUTH(0x050) /* RFPLL Control 28 (south) */
|
||||
#define B2062_S_RFPLL_CTL29 B43_LP_SOUTH(0x051) /* RFPLL Control 29 (south) */
|
||||
#define B2062_S_RFPLL_CTL30 B43_LP_SOUTH(0x052) /* RFPLL Control 30 (south) */
|
||||
#define B2062_S_RFPLL_CTL31 B43_LP_SOUTH(0x053) /* RFPLL Control 31 (south) */
|
||||
#define B2062_S_RFPLL_CTL32 B43_LP_SOUTH(0x054) /* RFPLL Control 32 (south) */
|
||||
#define B2062_S_RFPLL_CTL33 B43_LP_SOUTH(0x055) /* RFPLL Control 33 (south) */
|
||||
#define B2062_S_RFPLL_CTL34 B43_LP_SOUTH(0x056) /* RFPLL Control 34 (south) */
|
||||
#define B2062_S_RXG_CNT0 B43_LP_SOUTH(0x057) /* RXG Counter 00 (south) */
|
||||
#define B2062_S_RXG_CNT1 B43_LP_SOUTH(0x058) /* RXG Counter 01 (south) */
|
||||
#define B2062_S_RXG_CNT2 B43_LP_SOUTH(0x059) /* RXG Counter 02 (south) */
|
||||
#define B2062_S_RXG_CNT3 B43_LP_SOUTH(0x05A) /* RXG Counter 03 (south) */
|
||||
#define B2062_S_RXG_CNT4 B43_LP_SOUTH(0x05B) /* RXG Counter 04 (south) */
|
||||
#define B2062_S_RXG_CNT5 B43_LP_SOUTH(0x05C) /* RXG Counter 05 (south) */
|
||||
#define B2062_S_RXG_CNT6 B43_LP_SOUTH(0x05D) /* RXG Counter 06 (south) */
|
||||
#define B2062_S_RXG_CNT7 B43_LP_SOUTH(0x05E) /* RXG Counter 07 (south) */
|
||||
#define B2062_S_RXG_CNT8 B43_LP_SOUTH(0x05F) /* RXG Counter 08 (south) */
|
||||
#define B2062_S_RXG_CNT9 B43_LP_SOUTH(0x060) /* RXG Counter 09 (south) */
|
||||
#define B2062_S_RXG_CNT10 B43_LP_SOUTH(0x061) /* RXG Counter 10 (south) */
|
||||
#define B2062_S_RXG_CNT11 B43_LP_SOUTH(0x062) /* RXG Counter 11 (south) */
|
||||
#define B2062_S_RXG_CNT12 B43_LP_SOUTH(0x063) /* RXG Counter 12 (south) */
|
||||
#define B2062_S_RXG_CNT13 B43_LP_SOUTH(0x064) /* RXG Counter 13 (south) */
|
||||
#define B2062_S_RXG_CNT14 B43_LP_SOUTH(0x065) /* RXG Counter 14 (south) */
|
||||
#define B2062_S_RXG_CNT15 B43_LP_SOUTH(0x066) /* RXG Counter 15 (south) */
|
||||
#define B2062_S_RXG_CNT16 B43_LP_SOUTH(0x067) /* RXG Counter 16 (south) */
|
||||
#define B2062_S_RXG_CNT17 B43_LP_SOUTH(0x068) /* RXG Counter 17 (south) */
|
||||
|
||||
|
||||
|
||||
/*** Broadcom 2063 radio registers ***/
|
||||
#define B2063_RADIO_ID_CODE B43_LP_RADIO(0x001) /* Radio ID code */
|
||||
#define B2063_COMM1 B43_LP_RADIO(0x000) /* Common 01 */
|
||||
#define B2063_COMM2 B43_LP_RADIO(0x002) /* Common 02 */
|
||||
#define B2063_COMM3 B43_LP_RADIO(0x003) /* Common 03 */
|
||||
#define B2063_COMM4 B43_LP_RADIO(0x004) /* Common 04 */
|
||||
#define B2063_COMM5 B43_LP_RADIO(0x005) /* Common 05 */
|
||||
#define B2063_COMM6 B43_LP_RADIO(0x006) /* Common 06 */
|
||||
#define B2063_COMM7 B43_LP_RADIO(0x007) /* Common 07 */
|
||||
#define B2063_COMM8 B43_LP_RADIO(0x008) /* Common 08 */
|
||||
#define B2063_COMM9 B43_LP_RADIO(0x009) /* Common 09 */
|
||||
#define B2063_COMM10 B43_LP_RADIO(0x00A) /* Common 10 */
|
||||
#define B2063_COMM11 B43_LP_RADIO(0x00B) /* Common 11 */
|
||||
#define B2063_COMM12 B43_LP_RADIO(0x00C) /* Common 12 */
|
||||
#define B2063_COMM13 B43_LP_RADIO(0x00D) /* Common 13 */
|
||||
#define B2063_COMM14 B43_LP_RADIO(0x00E) /* Common 14 */
|
||||
#define B2063_COMM15 B43_LP_RADIO(0x00F) /* Common 15 */
|
||||
#define B2063_COMM16 B43_LP_RADIO(0x010) /* Common 16 */
|
||||
#define B2063_COMM17 B43_LP_RADIO(0x011) /* Common 17 */
|
||||
#define B2063_COMM18 B43_LP_RADIO(0x012) /* Common 18 */
|
||||
#define B2063_COMM19 B43_LP_RADIO(0x013) /* Common 19 */
|
||||
#define B2063_COMM20 B43_LP_RADIO(0x014) /* Common 20 */
|
||||
#define B2063_COMM21 B43_LP_RADIO(0x015) /* Common 21 */
|
||||
#define B2063_COMM22 B43_LP_RADIO(0x016) /* Common 22 */
|
||||
#define B2063_COMM23 B43_LP_RADIO(0x017) /* Common 23 */
|
||||
#define B2063_COMM24 B43_LP_RADIO(0x018) /* Common 24 */
|
||||
#define B2063_PWR_SWITCH_CTL B43_LP_RADIO(0x019) /* POWER SWITCH Control */
|
||||
#define B2063_PLL_SP1 B43_LP_RADIO(0x01A) /* PLL SP 1 */
|
||||
#define B2063_PLL_SP2 B43_LP_RADIO(0x01B) /* PLL SP 2 */
|
||||
#define B2063_LOGEN_SP1 B43_LP_RADIO(0x01C) /* LOGEN SP 1 */
|
||||
#define B2063_LOGEN_SP2 B43_LP_RADIO(0x01D) /* LOGEN SP 2 */
|
||||
#define B2063_LOGEN_SP3 B43_LP_RADIO(0x01E) /* LOGEN SP 3 */
|
||||
#define B2063_LOGEN_SP4 B43_LP_RADIO(0x01F) /* LOGEN SP 4 */
|
||||
#define B2063_LOGEN_SP5 B43_LP_RADIO(0x020) /* LOGEN SP 5 */
|
||||
#define B2063_G_RX_SP1 B43_LP_RADIO(0x021) /* G RX SP 1 */
|
||||
#define B2063_G_RX_SP2 B43_LP_RADIO(0x022) /* G RX SP 2 */
|
||||
#define B2063_G_RX_SP3 B43_LP_RADIO(0x023) /* G RX SP 3 */
|
||||
#define B2063_G_RX_SP4 B43_LP_RADIO(0x024) /* G RX SP 4 */
|
||||
#define B2063_G_RX_SP5 B43_LP_RADIO(0x025) /* G RX SP 5 */
|
||||
#define B2063_G_RX_SP6 B43_LP_RADIO(0x026) /* G RX SP 6 */
|
||||
#define B2063_G_RX_SP7 B43_LP_RADIO(0x027) /* G RX SP 7 */
|
||||
#define B2063_G_RX_SP8 B43_LP_RADIO(0x028) /* G RX SP 8 */
|
||||
#define B2063_G_RX_SP9 B43_LP_RADIO(0x029) /* G RX SP 9 */
|
||||
#define B2063_G_RX_SP10 B43_LP_RADIO(0x02A) /* G RX SP 10 */
|
||||
#define B2063_G_RX_SP11 B43_LP_RADIO(0x02B) /* G RX SP 11 */
|
||||
#define B2063_A_RX_SP1 B43_LP_RADIO(0x02C) /* A RX SP 1 */
|
||||
#define B2063_A_RX_SP2 B43_LP_RADIO(0x02D) /* A RX SP 2 */
|
||||
#define B2063_A_RX_SP3 B43_LP_RADIO(0x02E) /* A RX SP 3 */
|
||||
#define B2063_A_RX_SP4 B43_LP_RADIO(0x02F) /* A RX SP 4 */
|
||||
#define B2063_A_RX_SP5 B43_LP_RADIO(0x030) /* A RX SP 5 */
|
||||
#define B2063_A_RX_SP6 B43_LP_RADIO(0x031) /* A RX SP 6 */
|
||||
#define B2063_A_RX_SP7 B43_LP_RADIO(0x032) /* A RX SP 7 */
|
||||
#define B2063_RX_BB_SP1 B43_LP_RADIO(0x033) /* RX BB SP 1 */
|
||||
#define B2063_RX_BB_SP2 B43_LP_RADIO(0x034) /* RX BB SP 2 */
|
||||
#define B2063_RX_BB_SP3 B43_LP_RADIO(0x035) /* RX BB SP 3 */
|
||||
#define B2063_RX_BB_SP4 B43_LP_RADIO(0x036) /* RX BB SP 4 */
|
||||
#define B2063_RX_BB_SP5 B43_LP_RADIO(0x037) /* RX BB SP 5 */
|
||||
#define B2063_RX_BB_SP6 B43_LP_RADIO(0x038) /* RX BB SP 6 */
|
||||
#define B2063_RX_BB_SP7 B43_LP_RADIO(0x039) /* RX BB SP 7 */
|
||||
#define B2063_RX_BB_SP8 B43_LP_RADIO(0x03A) /* RX BB SP 8 */
|
||||
#define B2063_TX_RF_SP1 B43_LP_RADIO(0x03B) /* TX RF SP 1 */
|
||||
#define B2063_TX_RF_SP2 B43_LP_RADIO(0x03C) /* TX RF SP 2 */
|
||||
#define B2063_TX_RF_SP3 B43_LP_RADIO(0x03D) /* TX RF SP 3 */
|
||||
#define B2063_TX_RF_SP4 B43_LP_RADIO(0x03E) /* TX RF SP 4 */
|
||||
#define B2063_TX_RF_SP5 B43_LP_RADIO(0x03F) /* TX RF SP 5 */
|
||||
#define B2063_TX_RF_SP6 B43_LP_RADIO(0x040) /* TX RF SP 6 */
|
||||
#define B2063_TX_RF_SP7 B43_LP_RADIO(0x041) /* TX RF SP 7 */
|
||||
#define B2063_TX_RF_SP8 B43_LP_RADIO(0x042) /* TX RF SP 8 */
|
||||
#define B2063_TX_RF_SP9 B43_LP_RADIO(0x043) /* TX RF SP 9 */
|
||||
#define B2063_TX_RF_SP10 B43_LP_RADIO(0x044) /* TX RF SP 10 */
|
||||
#define B2063_TX_RF_SP11 B43_LP_RADIO(0x045) /* TX RF SP 11 */
|
||||
#define B2063_TX_RF_SP12 B43_LP_RADIO(0x046) /* TX RF SP 12 */
|
||||
#define B2063_TX_RF_SP13 B43_LP_RADIO(0x047) /* TX RF SP 13 */
|
||||
#define B2063_TX_RF_SP14 B43_LP_RADIO(0x048) /* TX RF SP 14 */
|
||||
#define B2063_TX_RF_SP15 B43_LP_RADIO(0x049) /* TX RF SP 15 */
|
||||
#define B2063_TX_RF_SP16 B43_LP_RADIO(0x04A) /* TX RF SP 16 */
|
||||
#define B2063_TX_RF_SP17 B43_LP_RADIO(0x04B) /* TX RF SP 17 */
|
||||
#define B2063_PA_SP1 B43_LP_RADIO(0x04C) /* PA SP 1 */
|
||||
#define B2063_PA_SP2 B43_LP_RADIO(0x04D) /* PA SP 2 */
|
||||
#define B2063_PA_SP3 B43_LP_RADIO(0x04E) /* PA SP 3 */
|
||||
#define B2063_PA_SP4 B43_LP_RADIO(0x04F) /* PA SP 4 */
|
||||
#define B2063_PA_SP5 B43_LP_RADIO(0x050) /* PA SP 5 */
|
||||
#define B2063_PA_SP6 B43_LP_RADIO(0x051) /* PA SP 6 */
|
||||
#define B2063_PA_SP7 B43_LP_RADIO(0x052) /* PA SP 7 */
|
||||
#define B2063_TX_BB_SP1 B43_LP_RADIO(0x053) /* TX BB SP 1 */
|
||||
#define B2063_TX_BB_SP2 B43_LP_RADIO(0x054) /* TX BB SP 2 */
|
||||
#define B2063_TX_BB_SP3 B43_LP_RADIO(0x055) /* TX BB SP 3 */
|
||||
#define B2063_REG_SP1 B43_LP_RADIO(0x056) /* REG SP 1 */
|
||||
#define B2063_BANDGAP_CTL1 B43_LP_RADIO(0x057) /* BANDGAP Control 1 */
|
||||
#define B2063_BANDGAP_CTL2 B43_LP_RADIO(0x058) /* BANDGAP Control 2 */
|
||||
#define B2063_LPO_CTL1 B43_LP_RADIO(0x059) /* LPO Control 1 */
|
||||
#define B2063_RC_CALIB_CTL1 B43_LP_RADIO(0x05A) /* RC Calibration Control 1 */
|
||||
#define B2063_RC_CALIB_CTL2 B43_LP_RADIO(0x05B) /* RC Calibration Control 2 */
|
||||
#define B2063_RC_CALIB_CTL3 B43_LP_RADIO(0x05C) /* RC Calibration Control 3 */
|
||||
#define B2063_RC_CALIB_CTL4 B43_LP_RADIO(0x05D) /* RC Calibration Control 4 */
|
||||
#define B2063_RC_CALIB_CTL5 B43_LP_RADIO(0x05E) /* RC Calibration Control 5 */
|
||||
#define B2063_RC_CALIB_CTL6 B43_LP_RADIO(0x05F) /* RC Calibration Control 6 */
|
||||
#define B2063_RC_CALIB_CTL7 B43_LP_RADIO(0x060) /* RC Calibration Control 7 */
|
||||
#define B2063_RC_CALIB_CTL8 B43_LP_RADIO(0x061) /* RC Calibration Control 8 */
|
||||
#define B2063_RC_CALIB_CTL9 B43_LP_RADIO(0x062) /* RC Calibration Control 9 */
|
||||
#define B2063_RC_CALIB_CTL10 B43_LP_RADIO(0x063) /* RC Calibration Control 10 */
|
||||
#define B2063_PLL_JTAG_CALNRST B43_LP_RADIO(0x064) /* PLL JTAG CALNRST */
|
||||
#define B2063_PLL_JTAG_IN_PLL1 B43_LP_RADIO(0x065) /* PLL JTAG IN PLL 1 */
|
||||
#define B2063_PLL_JTAG_IN_PLL2 B43_LP_RADIO(0x066) /* PLL JTAG IN PLL 2 */
|
||||
#define B2063_PLL_JTAG_PLL_CP1 B43_LP_RADIO(0x067) /* PLL JTAG PLL CP 1 */
|
||||
#define B2063_PLL_JTAG_PLL_CP2 B43_LP_RADIO(0x068) /* PLL JTAG PLL CP 2 */
|
||||
#define B2063_PLL_JTAG_PLL_CP3 B43_LP_RADIO(0x069) /* PLL JTAG PLL CP 3 */
|
||||
#define B2063_PLL_JTAG_PLL_CP4 B43_LP_RADIO(0x06A) /* PLL JTAG PLL CP 4 */
|
||||
#define B2063_PLL_JTAG_PLL_CTL1 B43_LP_RADIO(0x06B) /* PLL JTAG PLL Control 1 */
|
||||
#define B2063_PLL_JTAG_PLL_LF1 B43_LP_RADIO(0x06C) /* PLL JTAG PLL LF 1 */
|
||||
#define B2063_PLL_JTAG_PLL_LF2 B43_LP_RADIO(0x06D) /* PLL JTAG PLL LF 2 */
|
||||
#define B2063_PLL_JTAG_PLL_LF3 B43_LP_RADIO(0x06E) /* PLL JTAG PLL LF 3 */
|
||||
#define B2063_PLL_JTAG_PLL_LF4 B43_LP_RADIO(0x06F) /* PLL JTAG PLL LF 4 */
|
||||
#define B2063_PLL_JTAG_PLL_SG1 B43_LP_RADIO(0x070) /* PLL JTAG PLL SG 1 */
|
||||
#define B2063_PLL_JTAG_PLL_SG2 B43_LP_RADIO(0x071) /* PLL JTAG PLL SG 2 */
|
||||
#define B2063_PLL_JTAG_PLL_SG3 B43_LP_RADIO(0x072) /* PLL JTAG PLL SG 3 */
|
||||
#define B2063_PLL_JTAG_PLL_SG4 B43_LP_RADIO(0x073) /* PLL JTAG PLL SG 4 */
|
||||
#define B2063_PLL_JTAG_PLL_SG5 B43_LP_RADIO(0x074) /* PLL JTAG PLL SG 5 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO1 B43_LP_RADIO(0x075) /* PLL JTAG PLL VCO 1 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO2 B43_LP_RADIO(0x076) /* PLL JTAG PLL VCO 2 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB1 B43_LP_RADIO(0x077) /* PLL JTAG PLL VCO Calibration 1 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB2 B43_LP_RADIO(0x078) /* PLL JTAG PLL VCO Calibration 2 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB3 B43_LP_RADIO(0x079) /* PLL JTAG PLL VCO Calibration 3 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB4 B43_LP_RADIO(0x07A) /* PLL JTAG PLL VCO Calibration 4 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB5 B43_LP_RADIO(0x07B) /* PLL JTAG PLL VCO Calibration 5 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB6 B43_LP_RADIO(0x07C) /* PLL JTAG PLL VCO Calibration 6 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB7 B43_LP_RADIO(0x07D) /* PLL JTAG PLL VCO Calibration 7 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB8 B43_LP_RADIO(0x07E) /* PLL JTAG PLL VCO Calibration 8 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB9 B43_LP_RADIO(0x07F) /* PLL JTAG PLL VCO Calibration 9 */
|
||||
#define B2063_PLL_JTAG_PLL_VCO_CALIB10 B43_LP_RADIO(0x080) /* PLL JTAG PLL VCO Calibration 10 */
|
||||
#define B2063_PLL_JTAG_PLL_XTAL_12 B43_LP_RADIO(0x081) /* PLL JTAG PLL XTAL 1 2 */
|
||||
#define B2063_PLL_JTAG_PLL_XTAL3 B43_LP_RADIO(0x082) /* PLL JTAG PLL XTAL 3 */
|
||||
#define B2063_LOGEN_ACL1 B43_LP_RADIO(0x083) /* LOGEN ACL 1 */
|
||||
#define B2063_LOGEN_ACL2 B43_LP_RADIO(0x084) /* LOGEN ACL 2 */
|
||||
#define B2063_LOGEN_ACL3 B43_LP_RADIO(0x085) /* LOGEN ACL 3 */
|
||||
#define B2063_LOGEN_ACL4 B43_LP_RADIO(0x086) /* LOGEN ACL 4 */
|
||||
#define B2063_LOGEN_ACL5 B43_LP_RADIO(0x087) /* LOGEN ACL 5 */
|
||||
#define B2063_LO_CALIB_INPUTS B43_LP_RADIO(0x088) /* LO Calibration INPUTS */
|
||||
#define B2063_LO_CALIB_CTL1 B43_LP_RADIO(0x089) /* LO Calibration Control 1 */
|
||||
#define B2063_LO_CALIB_CTL2 B43_LP_RADIO(0x08A) /* LO Calibration Control 2 */
|
||||
#define B2063_LO_CALIB_CTL3 B43_LP_RADIO(0x08B) /* LO Calibration Control 3 */
|
||||
#define B2063_LO_CALIB_WAITCNT B43_LP_RADIO(0x08C) /* LO Calibration WAITCNT */
|
||||
#define B2063_LO_CALIB_OVR1 B43_LP_RADIO(0x08D) /* LO Calibration OVR 1 */
|
||||
#define B2063_LO_CALIB_OVR2 B43_LP_RADIO(0x08E) /* LO Calibration OVR 2 */
|
||||
#define B2063_LO_CALIB_OVAL1 B43_LP_RADIO(0x08F) /* LO Calibration OVAL 1 */
|
||||
#define B2063_LO_CALIB_OVAL2 B43_LP_RADIO(0x090) /* LO Calibration OVAL 2 */
|
||||
#define B2063_LO_CALIB_OVAL3 B43_LP_RADIO(0x091) /* LO Calibration OVAL 3 */
|
||||
#define B2063_LO_CALIB_OVAL4 B43_LP_RADIO(0x092) /* LO Calibration OVAL 4 */
|
||||
#define B2063_LO_CALIB_OVAL5 B43_LP_RADIO(0x093) /* LO Calibration OVAL 5 */
|
||||
#define B2063_LO_CALIB_OVAL6 B43_LP_RADIO(0x094) /* LO Calibration OVAL 6 */
|
||||
#define B2063_LO_CALIB_OVAL7 B43_LP_RADIO(0x095) /* LO Calibration OVAL 7 */
|
||||
#define B2063_LO_CALIB_CALVLD1 B43_LP_RADIO(0x096) /* LO Calibration CALVLD 1 */
|
||||
#define B2063_LO_CALIB_CALVLD2 B43_LP_RADIO(0x097) /* LO Calibration CALVLD 2 */
|
||||
#define B2063_LO_CALIB_CVAL1 B43_LP_RADIO(0x098) /* LO Calibration CVAL 1 */
|
||||
#define B2063_LO_CALIB_CVAL2 B43_LP_RADIO(0x099) /* LO Calibration CVAL 2 */
|
||||
#define B2063_LO_CALIB_CVAL3 B43_LP_RADIO(0x09A) /* LO Calibration CVAL 3 */
|
||||
#define B2063_LO_CALIB_CVAL4 B43_LP_RADIO(0x09B) /* LO Calibration CVAL 4 */
|
||||
#define B2063_LO_CALIB_CVAL5 B43_LP_RADIO(0x09C) /* LO Calibration CVAL 5 */
|
||||
#define B2063_LO_CALIB_CVAL6 B43_LP_RADIO(0x09D) /* LO Calibration CVAL 6 */
|
||||
#define B2063_LO_CALIB_CVAL7 B43_LP_RADIO(0x09E) /* LO Calibration CVAL 7 */
|
||||
#define B2063_LOGEN_CALIB_EN B43_LP_RADIO(0x09F) /* LOGEN Calibration EN */
|
||||
#define B2063_LOGEN_PEAKDET1 B43_LP_RADIO(0x0A0) /* LOGEN PEAKDET 1 */
|
||||
#define B2063_LOGEN_RCCR1 B43_LP_RADIO(0x0A1) /* LOGEN RCCR 1 */
|
||||
#define B2063_LOGEN_VCOBUF1 B43_LP_RADIO(0x0A2) /* LOGEN VCOBUF 1 */
|
||||
#define B2063_LOGEN_MIXER1 B43_LP_RADIO(0x0A3) /* LOGEN MIXER 1 */
|
||||
#define B2063_LOGEN_MIXER2 B43_LP_RADIO(0x0A4) /* LOGEN MIXER 2 */
|
||||
#define B2063_LOGEN_BUF1 B43_LP_RADIO(0x0A5) /* LOGEN BUF 1 */
|
||||
#define B2063_LOGEN_BUF2 B43_LP_RADIO(0x0A6) /* LOGEN BUF 2 */
|
||||
#define B2063_LOGEN_DIV1 B43_LP_RADIO(0x0A7) /* LOGEN DIV 1 */
|
||||
#define B2063_LOGEN_DIV2 B43_LP_RADIO(0x0A8) /* LOGEN DIV 2 */
|
||||
#define B2063_LOGEN_DIV3 B43_LP_RADIO(0x0A9) /* LOGEN DIV 3 */
|
||||
#define B2063_LOGEN_CBUFRX1 B43_LP_RADIO(0x0AA) /* LOGEN CBUFRX 1 */
|
||||
#define B2063_LOGEN_CBUFRX2 B43_LP_RADIO(0x0AB) /* LOGEN CBUFRX 2 */
|
||||
#define B2063_LOGEN_CBUFTX1 B43_LP_RADIO(0x0AC) /* LOGEN CBUFTX 1 */
|
||||
#define B2063_LOGEN_CBUFTX2 B43_LP_RADIO(0x0AD) /* LOGEN CBUFTX 2 */
|
||||
#define B2063_LOGEN_IDAC1 B43_LP_RADIO(0x0AE) /* LOGEN IDAC 1 */
|
||||
#define B2063_LOGEN_SPARE1 B43_LP_RADIO(0x0AF) /* LOGEN SPARE 1 */
|
||||
#define B2063_LOGEN_SPARE2 B43_LP_RADIO(0x0B0) /* LOGEN SPARE 2 */
|
||||
#define B2063_LOGEN_SPARE3 B43_LP_RADIO(0x0B1) /* LOGEN SPARE 3 */
|
||||
#define B2063_G_RX_1ST1 B43_LP_RADIO(0x0B2) /* G RX 1ST 1 */
|
||||
#define B2063_G_RX_1ST2 B43_LP_RADIO(0x0B3) /* G RX 1ST 2 */
|
||||
#define B2063_G_RX_1ST3 B43_LP_RADIO(0x0B4) /* G RX 1ST 3 */
|
||||
#define B2063_G_RX_2ND1 B43_LP_RADIO(0x0B5) /* G RX 2ND 1 */
|
||||
#define B2063_G_RX_2ND2 B43_LP_RADIO(0x0B6) /* G RX 2ND 2 */
|
||||
#define B2063_G_RX_2ND3 B43_LP_RADIO(0x0B7) /* G RX 2ND 3 */
|
||||
#define B2063_G_RX_2ND4 B43_LP_RADIO(0x0B8) /* G RX 2ND 4 */
|
||||
#define B2063_G_RX_2ND5 B43_LP_RADIO(0x0B9) /* G RX 2ND 5 */
|
||||
#define B2063_G_RX_2ND6 B43_LP_RADIO(0x0BA) /* G RX 2ND 6 */
|
||||
#define B2063_G_RX_2ND7 B43_LP_RADIO(0x0BB) /* G RX 2ND 7 */
|
||||
#define B2063_G_RX_2ND8 B43_LP_RADIO(0x0BC) /* G RX 2ND 8 */
|
||||
#define B2063_G_RX_PS1 B43_LP_RADIO(0x0BD) /* G RX PS 1 */
|
||||
#define B2063_G_RX_PS2 B43_LP_RADIO(0x0BE) /* G RX PS 2 */
|
||||
#define B2063_G_RX_PS3 B43_LP_RADIO(0x0BF) /* G RX PS 3 */
|
||||
#define B2063_G_RX_PS4 B43_LP_RADIO(0x0C0) /* G RX PS 4 */
|
||||
#define B2063_G_RX_PS5 B43_LP_RADIO(0x0C1) /* G RX PS 5 */
|
||||
#define B2063_G_RX_MIX1 B43_LP_RADIO(0x0C2) /* G RX MIX 1 */
|
||||
#define B2063_G_RX_MIX2 B43_LP_RADIO(0x0C3) /* G RX MIX 2 */
|
||||
#define B2063_G_RX_MIX3 B43_LP_RADIO(0x0C4) /* G RX MIX 3 */
|
||||
#define B2063_G_RX_MIX4 B43_LP_RADIO(0x0C5) /* G RX MIX 4 */
|
||||
#define B2063_G_RX_MIX5 B43_LP_RADIO(0x0C6) /* G RX MIX 5 */
|
||||
#define B2063_G_RX_MIX6 B43_LP_RADIO(0x0C7) /* G RX MIX 6 */
|
||||
#define B2063_G_RX_MIX7 B43_LP_RADIO(0x0C8) /* G RX MIX 7 */
|
||||
#define B2063_G_RX_MIX8 B43_LP_RADIO(0x0C9) /* G RX MIX 8 */
|
||||
#define B2063_G_RX_PDET1 B43_LP_RADIO(0x0CA) /* G RX PDET 1 */
|
||||
#define B2063_G_RX_SPARES1 B43_LP_RADIO(0x0CB) /* G RX SPARES 1 */
|
||||
#define B2063_G_RX_SPARES2 B43_LP_RADIO(0x0CC) /* G RX SPARES 2 */
|
||||
#define B2063_G_RX_SPARES3 B43_LP_RADIO(0x0CD) /* G RX SPARES 3 */
|
||||
#define B2063_A_RX_1ST1 B43_LP_RADIO(0x0CE) /* A RX 1ST 1 */
|
||||
#define B2063_A_RX_1ST2 B43_LP_RADIO(0x0CF) /* A RX 1ST 2 */
|
||||
#define B2063_A_RX_1ST3 B43_LP_RADIO(0x0D0) /* A RX 1ST 3 */
|
||||
#define B2063_A_RX_1ST4 B43_LP_RADIO(0x0D1) /* A RX 1ST 4 */
|
||||
#define B2063_A_RX_1ST5 B43_LP_RADIO(0x0D2) /* A RX 1ST 5 */
|
||||
#define B2063_A_RX_2ND1 B43_LP_RADIO(0x0D3) /* A RX 2ND 1 */
|
||||
#define B2063_A_RX_2ND2 B43_LP_RADIO(0x0D4) /* A RX 2ND 2 */
|
||||
#define B2063_A_RX_2ND3 B43_LP_RADIO(0x0D5) /* A RX 2ND 3 */
|
||||
#define B2063_A_RX_2ND4 B43_LP_RADIO(0x0D6) /* A RX 2ND 4 */
|
||||
#define B2063_A_RX_2ND5 B43_LP_RADIO(0x0D7) /* A RX 2ND 5 */
|
||||
#define B2063_A_RX_2ND6 B43_LP_RADIO(0x0D8) /* A RX 2ND 6 */
|
||||
#define B2063_A_RX_2ND7 B43_LP_RADIO(0x0D9) /* A RX 2ND 7 */
|
||||
#define B2063_A_RX_PS1 B43_LP_RADIO(0x0DA) /* A RX PS 1 */
|
||||
#define B2063_A_RX_PS2 B43_LP_RADIO(0x0DB) /* A RX PS 2 */
|
||||
#define B2063_A_RX_PS3 B43_LP_RADIO(0x0DC) /* A RX PS 3 */
|
||||
#define B2063_A_RX_PS4 B43_LP_RADIO(0x0DD) /* A RX PS 4 */
|
||||
#define B2063_A_RX_PS5 B43_LP_RADIO(0x0DE) /* A RX PS 5 */
|
||||
#define B2063_A_RX_PS6 B43_LP_RADIO(0x0DF) /* A RX PS 6 */
|
||||
#define B2063_A_RX_MIX1 B43_LP_RADIO(0x0E0) /* A RX MIX 1 */
|
||||
#define B2063_A_RX_MIX2 B43_LP_RADIO(0x0E1) /* A RX MIX 2 */
|
||||
#define B2063_A_RX_MIX3 B43_LP_RADIO(0x0E2) /* A RX MIX 3 */
|
||||
#define B2063_A_RX_MIX4 B43_LP_RADIO(0x0E3) /* A RX MIX 4 */
|
||||
#define B2063_A_RX_MIX5 B43_LP_RADIO(0x0E4) /* A RX MIX 5 */
|
||||
#define B2063_A_RX_MIX6 B43_LP_RADIO(0x0E5) /* A RX MIX 6 */
|
||||
#define B2063_A_RX_MIX7 B43_LP_RADIO(0x0E6) /* A RX MIX 7 */
|
||||
#define B2063_A_RX_MIX8 B43_LP_RADIO(0x0E7) /* A RX MIX 8 */
|
||||
#define B2063_A_RX_PWRDET1 B43_LP_RADIO(0x0E8) /* A RX PWRDET 1 */
|
||||
#define B2063_A_RX_SPARE1 B43_LP_RADIO(0x0E9) /* A RX SPARE 1 */
|
||||
#define B2063_A_RX_SPARE2 B43_LP_RADIO(0x0EA) /* A RX SPARE 2 */
|
||||
#define B2063_A_RX_SPARE3 B43_LP_RADIO(0x0EB) /* A RX SPARE 3 */
|
||||
#define B2063_RX_TIA_CTL1 B43_LP_RADIO(0x0EC) /* RX TIA Control 1 */
|
||||
#define B2063_RX_TIA_CTL2 B43_LP_RADIO(0x0ED) /* RX TIA Control 2 */
|
||||
#define B2063_RX_TIA_CTL3 B43_LP_RADIO(0x0EE) /* RX TIA Control 3 */
|
||||
#define B2063_RX_TIA_CTL4 B43_LP_RADIO(0x0EF) /* RX TIA Control 4 */
|
||||
#define B2063_RX_TIA_CTL5 B43_LP_RADIO(0x0F0) /* RX TIA Control 5 */
|
||||
#define B2063_RX_TIA_CTL6 B43_LP_RADIO(0x0F1) /* RX TIA Control 6 */
|
||||
#define B2063_RX_BB_CTL1 B43_LP_RADIO(0x0F2) /* RX BB Control 1 */
|
||||
#define B2063_RX_BB_CTL2 B43_LP_RADIO(0x0F3) /* RX BB Control 2 */
|
||||
#define B2063_RX_BB_CTL3 B43_LP_RADIO(0x0F4) /* RX BB Control 3 */
|
||||
#define B2063_RX_BB_CTL4 B43_LP_RADIO(0x0F5) /* RX BB Control 4 */
|
||||
#define B2063_RX_BB_CTL5 B43_LP_RADIO(0x0F6) /* RX BB Control 5 */
|
||||
#define B2063_RX_BB_CTL6 B43_LP_RADIO(0x0F7) /* RX BB Control 6 */
|
||||
#define B2063_RX_BB_CTL7 B43_LP_RADIO(0x0F8) /* RX BB Control 7 */
|
||||
#define B2063_RX_BB_CTL8 B43_LP_RADIO(0x0F9) /* RX BB Control 8 */
|
||||
#define B2063_RX_BB_CTL9 B43_LP_RADIO(0x0FA) /* RX BB Control 9 */
|
||||
#define B2063_TX_RF_CTL1 B43_LP_RADIO(0x0FB) /* TX RF Control 1 */
|
||||
#define B2063_TX_RF_IDAC_LO_RF_I B43_LP_RADIO(0x0FC) /* TX RF IDAC LO RF I */
|
||||
#define B2063_TX_RF_IDAC_LO_RF_Q B43_LP_RADIO(0x0FD) /* TX RF IDAC LO RF Q */
|
||||
#define B2063_TX_RF_IDAC_LO_BB_I B43_LP_RADIO(0x0FE) /* TX RF IDAC LO BB I */
|
||||
#define B2063_TX_RF_IDAC_LO_BB_Q B43_LP_RADIO(0x0FF) /* TX RF IDAC LO BB Q */
|
||||
#define B2063_TX_RF_CTL2 B43_LP_RADIO(0x100) /* TX RF Control 2 */
|
||||
#define B2063_TX_RF_CTL3 B43_LP_RADIO(0x101) /* TX RF Control 3 */
|
||||
#define B2063_TX_RF_CTL4 B43_LP_RADIO(0x102) /* TX RF Control 4 */
|
||||
#define B2063_TX_RF_CTL5 B43_LP_RADIO(0x103) /* TX RF Control 5 */
|
||||
#define B2063_TX_RF_CTL6 B43_LP_RADIO(0x104) /* TX RF Control 6 */
|
||||
#define B2063_TX_RF_CTL7 B43_LP_RADIO(0x105) /* TX RF Control 7 */
|
||||
#define B2063_TX_RF_CTL8 B43_LP_RADIO(0x106) /* TX RF Control 8 */
|
||||
#define B2063_TX_RF_CTL9 B43_LP_RADIO(0x107) /* TX RF Control 9 */
|
||||
#define B2063_TX_RF_CTL10 B43_LP_RADIO(0x108) /* TX RF Control 10 */
|
||||
#define B2063_TX_RF_CTL14 B43_LP_RADIO(0x109) /* TX RF Control 14 */
|
||||
#define B2063_TX_RF_CTL15 B43_LP_RADIO(0x10A) /* TX RF Control 15 */
|
||||
#define B2063_PA_CTL1 B43_LP_RADIO(0x10B) /* PA Control 1 */
|
||||
#define B2063_PA_CTL2 B43_LP_RADIO(0x10C) /* PA Control 2 */
|
||||
#define B2063_PA_CTL3 B43_LP_RADIO(0x10D) /* PA Control 3 */
|
||||
#define B2063_PA_CTL4 B43_LP_RADIO(0x10E) /* PA Control 4 */
|
||||
#define B2063_PA_CTL5 B43_LP_RADIO(0x10F) /* PA Control 5 */
|
||||
#define B2063_PA_CTL6 B43_LP_RADIO(0x110) /* PA Control 6 */
|
||||
#define B2063_PA_CTL7 B43_LP_RADIO(0x111) /* PA Control 7 */
|
||||
#define B2063_PA_CTL8 B43_LP_RADIO(0x112) /* PA Control 8 */
|
||||
#define B2063_PA_CTL9 B43_LP_RADIO(0x113) /* PA Control 9 */
|
||||
#define B2063_PA_CTL10 B43_LP_RADIO(0x114) /* PA Control 10 */
|
||||
#define B2063_PA_CTL11 B43_LP_RADIO(0x115) /* PA Control 11 */
|
||||
#define B2063_PA_CTL12 B43_LP_RADIO(0x116) /* PA Control 12 */
|
||||
#define B2063_PA_CTL13 B43_LP_RADIO(0x117) /* PA Control 13 */
|
||||
#define B2063_TX_BB_CTL1 B43_LP_RADIO(0x118) /* TX BB Control 1 */
|
||||
#define B2063_TX_BB_CTL2 B43_LP_RADIO(0x119) /* TX BB Control 2 */
|
||||
#define B2063_TX_BB_CTL3 B43_LP_RADIO(0x11A) /* TX BB Control 3 */
|
||||
#define B2063_TX_BB_CTL4 B43_LP_RADIO(0x11B) /* TX BB Control 4 */
|
||||
#define B2063_GPIO_CTL1 B43_LP_RADIO(0x11C) /* GPIO Control 1 */
|
||||
#define B2063_VREG_CTL1 B43_LP_RADIO(0x11D) /* VREG Control 1 */
|
||||
#define B2063_AMUX_CTL1 B43_LP_RADIO(0x11E) /* AMUX Control 1 */
|
||||
#define B2063_IQ_CALIB_GVAR B43_LP_RADIO(0x11F) /* IQ Calibration GVAR */
|
||||
#define B2063_IQ_CALIB_CTL1 B43_LP_RADIO(0x120) /* IQ Calibration Control 1 */
|
||||
#define B2063_IQ_CALIB_CTL2 B43_LP_RADIO(0x121) /* IQ Calibration Control 2 */
|
||||
#define B2063_TEMPSENSE_CTL1 B43_LP_RADIO(0x122) /* TEMPSENSE Control 1 */
|
||||
#define B2063_TEMPSENSE_CTL2 B43_LP_RADIO(0x123) /* TEMPSENSE Control 2 */
|
||||
#define B2063_TX_RX_LOOPBACK1 B43_LP_RADIO(0x124) /* TX/RX LOOPBACK 1 */
|
||||
#define B2063_TX_RX_LOOPBACK2 B43_LP_RADIO(0x125) /* TX/RX LOOPBACK 2 */
|
||||
#define B2063_EXT_TSSI_CTL1 B43_LP_RADIO(0x126) /* EXT TSSI Control 1 */
|
||||
#define B2063_EXT_TSSI_CTL2 B43_LP_RADIO(0x127) /* EXT TSSI Control 2 */
|
||||
#define B2063_AFE_CTL B43_LP_RADIO(0x128) /* AFE Control */
|
||||
|
||||
|
||||
|
||||
struct b43_phy_lp {
|
||||
//TODO
|
||||
};
|
||||
|
||||
|
||||
struct b43_phy_operations;
|
||||
extern const struct b43_phy_operations b43_phyops_lp;
|
||||
|
||||
#endif /* LINUX_B43_PHY_LP_H_ */
|
|
@ -26,7 +26,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#include "b43.h"
|
||||
#include "nphy.h"
|
||||
#include "phy_n.h"
|
||||
#include "tables_nphy.h"
|
||||
|
||||
|
||||
|
@ -499,35 +499,31 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev)
|
|||
return -ENOMEM;
|
||||
dev->phy.n = nphy;
|
||||
|
||||
//TODO init struct b43_phy_n
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = phy->n;
|
||||
|
||||
memset(nphy, 0, sizeof(*nphy));
|
||||
|
||||
//TODO init struct b43_phy_n
|
||||
}
|
||||
|
||||
static void b43_nphy_op_free(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
struct b43_phy_n *nphy = phy->n;
|
||||
|
||||
kfree(nphy);
|
||||
phy->n = NULL;
|
||||
}
|
||||
|
||||
static int b43_nphy_op_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
int err;
|
||||
|
||||
err = b43_phy_initn(dev);
|
||||
if (err)
|
||||
return err;
|
||||
nphy->initialised = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_nphy_op_exit(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_phy_n *nphy = dev->phy.n;
|
||||
|
||||
if (nphy->initialised) {
|
||||
//TODO
|
||||
nphy->initialised = 0;
|
||||
}
|
||||
//TODO
|
||||
kfree(nphy);
|
||||
dev->phy.n = NULL;
|
||||
return b43_phy_initn(dev);
|
||||
}
|
||||
|
||||
static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
|
||||
|
@ -587,6 +583,12 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
|
|||
{//TODO
|
||||
}
|
||||
|
||||
static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
|
||||
{
|
||||
b43_phy_write(dev, B43_NPHY_AFECTL_OVER,
|
||||
on ? 0 : 0x7FFF);
|
||||
}
|
||||
|
||||
static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
|
||||
unsigned int new_channel)
|
||||
{
|
||||
|
@ -610,13 +612,15 @@ static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev)
|
|||
|
||||
const struct b43_phy_operations b43_phyops_n = {
|
||||
.allocate = b43_nphy_op_allocate,
|
||||
.free = b43_nphy_op_free,
|
||||
.prepare_structs = b43_nphy_op_prepare_structs,
|
||||
.init = b43_nphy_op_init,
|
||||
.exit = b43_nphy_op_exit,
|
||||
.phy_read = b43_nphy_op_read,
|
||||
.phy_write = b43_nphy_op_write,
|
||||
.radio_read = b43_nphy_op_radio_read,
|
||||
.radio_write = b43_nphy_op_radio_write,
|
||||
.software_rfkill = b43_nphy_op_software_rfkill,
|
||||
.switch_analog = b43_nphy_op_switch_analog,
|
||||
.switch_channel = b43_nphy_op_switch_channel,
|
||||
.get_default_chan = b43_nphy_op_get_default_chan,
|
||||
.recalc_txpower = b43_nphy_op_recalc_txpower,
|
|
@ -920,8 +920,6 @@
|
|||
struct b43_wldev;
|
||||
|
||||
struct b43_phy_n {
|
||||
bool initialised;
|
||||
|
||||
//TODO lots of missing stuff
|
||||
};
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include "b43.h"
|
||||
#include "tables_nphy.h"
|
||||
#include "phy_common.h"
|
||||
#include "nphy.h"
|
||||
#include "phy_n.h"
|
||||
|
||||
|
||||
struct b2055_inittab_entry {
|
||||
|
|
|
@ -3704,6 +3704,11 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
|
|||
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_WDS) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
hw->queues = 1; /* FIXME: hardware has more queues */
|
||||
SET_IEEE80211_DEV(hw, dev->dev);
|
||||
if (is_valid_ether_addr(sprom->et1mac))
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define _iwl3945_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
|
||||
#define _iwl3945_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
|
||||
#ifdef CONFIG_IWL3945_DEBUG
|
||||
static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *priv,
|
||||
u32 ofs, u32 val)
|
||||
|
@ -73,14 +73,14 @@ static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *
|
|||
#define iwl3945_write32(priv, ofs, val) _iwl3945_write32(priv, ofs, val)
|
||||
#endif
|
||||
|
||||
#define _iwl3945_read32(priv, ofs) readl((priv)->hw_base + (ofs))
|
||||
#define _iwl3945_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
|
||||
#ifdef CONFIG_IWL3945_DEBUG
|
||||
static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *priv, u32 ofs)
|
||||
{
|
||||
IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
|
||||
return _iwl3945_read32(priv, ofs);
|
||||
}
|
||||
#define iwl3945_read32(priv, ofs) __iwl3945_read32(__FILE__, __LINE__, priv, ofs)
|
||||
#define iwl3945_read32(priv, ofs)__iwl3945_read32(__FILE__, __LINE__, priv, ofs)
|
||||
#else
|
||||
#define iwl3945_read32(p, o) _iwl3945_read32(p, o)
|
||||
#endif
|
||||
|
@ -153,28 +153,10 @@ static inline void __iwl3945_clear_bit(const char *f, u32 l,
|
|||
static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 gp_ctl;
|
||||
|
||||
#ifdef CONFIG_IWL3945_DEBUG
|
||||
if (atomic_read(&priv->restrict_refcnt))
|
||||
return 0;
|
||||
#endif
|
||||
if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
|
||||
test_bit(STATUS_RF_KILL_SW, &priv->status)) {
|
||||
IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
|
||||
"wakes up NIC\n");
|
||||
|
||||
/* 10 msec allows time for NIC to complete its data save */
|
||||
gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL);
|
||||
if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
|
||||
IWL_DEBUG_RF_KILL("Wait for complete power-down, "
|
||||
"gpctl = 0x%08x\n", gp_ctl);
|
||||
mdelay(10);
|
||||
} else
|
||||
IWL_DEBUG_RF_KILL("power-down complete, "
|
||||
"gpctl = 0x%08x\n", gp_ctl);
|
||||
}
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
_iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL,
|
||||
|
|
|
@ -688,87 +688,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
|
|||
|
||||
switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
|
||||
case IEEE80211_FTYPE_MGMT:
|
||||
switch (le16_to_cpu(header->frame_control) &
|
||||
IEEE80211_FCTL_STYPE) {
|
||||
case IEEE80211_STYPE_PROBE_RESP:
|
||||
case IEEE80211_STYPE_BEACON:{
|
||||
/* If this is a beacon or probe response for
|
||||
* our network then cache the beacon
|
||||
* timestamp */
|
||||
if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
|
||||
&& !compare_ether_addr(header->addr2,
|
||||
priv->bssid)) ||
|
||||
((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
|
||||
&& !compare_ether_addr(header->addr3,
|
||||
priv->bssid)))) {
|
||||
struct ieee80211_mgmt *mgmt =
|
||||
(struct ieee80211_mgmt *)header;
|
||||
__le32 *pos;
|
||||
pos = (__le32 *)&mgmt->u.beacon.
|
||||
timestamp;
|
||||
priv->timestamp0 = le32_to_cpu(pos[0]);
|
||||
priv->timestamp1 = le32_to_cpu(pos[1]);
|
||||
priv->beacon_int = le16_to_cpu(
|
||||
mgmt->u.beacon.beacon_int);
|
||||
if (priv->call_post_assoc_from_beacon &&
|
||||
(priv->iw_mode ==
|
||||
IEEE80211_IF_TYPE_STA))
|
||||
queue_work(priv->workqueue,
|
||||
&priv->post_associate.work);
|
||||
|
||||
priv->call_post_assoc_from_beacon = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
/* TODO: Parse 802.11h frames for CSA... */
|
||||
break;
|
||||
|
||||
/*
|
||||
* TODO: Use the new callback function from
|
||||
* mac80211 instead of sniffing these packets.
|
||||
*/
|
||||
case IEEE80211_STYPE_ASSOC_RESP:
|
||||
case IEEE80211_STYPE_REASSOC_RESP:{
|
||||
struct ieee80211_mgmt *mgnt =
|
||||
(struct ieee80211_mgmt *)header;
|
||||
|
||||
/* We have just associated, give some
|
||||
* time for the 4-way handshake if
|
||||
* any. Don't start scan too early. */
|
||||
priv->next_scan_jiffies = jiffies +
|
||||
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
|
||||
|
||||
priv->assoc_id = (~((1 << 15) | (1 << 14)) &
|
||||
le16_to_cpu(mgnt->u.
|
||||
assoc_resp.aid));
|
||||
priv->assoc_capability =
|
||||
le16_to_cpu(mgnt->u.assoc_resp.capab_info);
|
||||
if (priv->beacon_int)
|
||||
queue_work(priv->workqueue,
|
||||
&priv->post_associate.work);
|
||||
else
|
||||
priv->call_post_assoc_from_beacon = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case IEEE80211_STYPE_PROBE_REQ:{
|
||||
DECLARE_MAC_BUF(mac1);
|
||||
DECLARE_MAC_BUF(mac2);
|
||||
DECLARE_MAC_BUF(mac3);
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
|
||||
IWL_DEBUG_DROP
|
||||
("Dropping (non network): %s"
|
||||
", %s, %s\n",
|
||||
print_mac(mac1, header->addr1),
|
||||
print_mac(mac2, header->addr2),
|
||||
print_mac(mac3, header->addr3));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
case IEEE80211_FTYPE_DATA:
|
||||
/* fall through */
|
||||
default:
|
||||
|
|
|
@ -894,7 +894,6 @@ struct iwl3945_priv {
|
|||
struct delayed_work thermal_periodic;
|
||||
struct delayed_work gather_stats;
|
||||
struct delayed_work scan_check;
|
||||
struct delayed_work post_associate;
|
||||
|
||||
#define IWL_DEFAULT_TX_POWER 0x0F
|
||||
s8 user_txpower_limit;
|
||||
|
|
|
@ -98,16 +98,17 @@
|
|||
#define IWL_RSSI_OFFSET 44
|
||||
|
||||
|
||||
#include "iwl-commands.h"
|
||||
|
||||
/* PCI registers */
|
||||
#define PCI_LINK_CTRL 0x0F0 /* 1 byte */
|
||||
#define PCI_POWER_SOURCE 0x0C8
|
||||
#define PCI_REG_WUM8 0x0E8
|
||||
#define PCI_CFG_RETRY_TIMEOUT 0x041
|
||||
#define PCI_CFG_POWER_SOURCE 0x0C8
|
||||
#define PCI_REG_WUM8 0x0E8
|
||||
#define PCI_CFG_LINK_CTRL 0x0F0
|
||||
|
||||
/* PCI register values */
|
||||
#define PCI_LINK_VAL_L0S_EN 0x01
|
||||
#define PCI_LINK_VAL_L1_EN 0x02
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L0S_EN 0x01
|
||||
#define PCI_CFG_LINK_CTRL_VAL_L1_EN 0x02
|
||||
#define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04
|
||||
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
|
||||
|
||||
#define TFD_QUEUE_SIZE_MAX (256)
|
||||
|
|
|
@ -399,7 +399,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
|
|||
unsigned long flags;
|
||||
u32 val;
|
||||
u16 radio_cfg;
|
||||
u8 val_link;
|
||||
u16 link;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
|
@ -410,10 +410,10 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
|
|||
val & ~(1 << 11));
|
||||
}
|
||||
|
||||
pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
|
||||
|
||||
/* L1 is enabled by BIOS */
|
||||
if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
|
||||
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* diable L0S disabled L1A enabled */
|
||||
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
else
|
||||
|
|
|
@ -129,6 +129,13 @@ struct iwl5000_shared {
|
|||
__le32 padding2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* calibrations defined for 5000 */
|
||||
/* defines the order in which results should be sent to the runtime uCode */
|
||||
enum iwl5000_calib {
|
||||
IWL5000_CALIB_LO,
|
||||
IWL5000_CALIB_TX_IQ,
|
||||
IWL5000_CALIB_TX_IQ_PERD,
|
||||
};
|
||||
|
||||
#endif /* __iwl_5000_hw_h__ */
|
||||
|
||||
|
|
|
@ -208,14 +208,14 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
|
|||
{
|
||||
unsigned long flags;
|
||||
u16 radio_cfg;
|
||||
u8 val_link;
|
||||
u16 link;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &link);
|
||||
|
||||
/* L1 is enabled by BIOS */
|
||||
if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
|
||||
if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN)
|
||||
/* diable L0S disabled L1A enabled */
|
||||
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
else
|
||||
|
@ -444,48 +444,6 @@ static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
|
|||
sizeof(cal_cmd), &cal_cmd);
|
||||
}
|
||||
|
||||
static int iwl5000_send_calib_results(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_PHY_CALIBRATION_CMD,
|
||||
.meta.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
|
||||
if (priv->calib_results.lo_res) {
|
||||
hcmd.len = priv->calib_results.lo_res_len;
|
||||
hcmd.data = priv->calib_results.lo_res;
|
||||
ret = iwl_send_cmd_sync(priv, &hcmd);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (priv->calib_results.tx_iq_res) {
|
||||
hcmd.len = priv->calib_results.tx_iq_res_len;
|
||||
hcmd.data = priv->calib_results.tx_iq_res;
|
||||
ret = iwl_send_cmd_sync(priv, &hcmd);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (priv->calib_results.tx_iq_perd_res) {
|
||||
hcmd.len = priv->calib_results.tx_iq_perd_res_len;
|
||||
hcmd.data = priv->calib_results.tx_iq_perd_res;
|
||||
ret = iwl_send_cmd_sync(priv, &hcmd);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
IWL_ERROR("Error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
|
||||
{
|
||||
struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
|
||||
|
@ -510,33 +468,30 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv,
|
|||
struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
|
||||
struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
|
||||
int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
|
||||
iwl_free_calib_results(priv);
|
||||
int index;
|
||||
|
||||
/* reduce the size of the length field itself */
|
||||
len -= 4;
|
||||
|
||||
/* Define the order in which the results will be sent to the runtime
|
||||
* uCode. iwl_send_calib_results sends them in a row according to their
|
||||
* index. We sort them here */
|
||||
switch (hdr->op_code) {
|
||||
case IWL5000_PHY_CALIBRATE_LO_CMD:
|
||||
priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
|
||||
priv->calib_results.lo_res_len = len;
|
||||
memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
|
||||
index = IWL5000_CALIB_LO;
|
||||
break;
|
||||
case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
|
||||
priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
|
||||
priv->calib_results.tx_iq_res_len = len;
|
||||
memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
|
||||
index = IWL5000_CALIB_TX_IQ;
|
||||
break;
|
||||
case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
|
||||
priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
|
||||
priv->calib_results.tx_iq_perd_res_len = len;
|
||||
memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
|
||||
index = IWL5000_CALIB_TX_IQ_PERD;
|
||||
break;
|
||||
default:
|
||||
IWL_ERROR("Unknown calibration notification %d\n",
|
||||
hdr->op_code);
|
||||
return;
|
||||
}
|
||||
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
|
||||
}
|
||||
|
||||
static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
|
||||
|
@ -834,7 +789,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
|
|||
iwl5000_send_Xtal_calib(priv);
|
||||
|
||||
if (priv->ucode_type == UCODE_RT)
|
||||
iwl5000_send_calib_results(priv);
|
||||
iwl_send_calib_results(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1668,6 +1668,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
|||
return;
|
||||
|
||||
lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
|
||||
lq_sta->supp_rates = sta->supp_rates[lq_sta->band];
|
||||
|
||||
tid = rs_tl_add_packet(lq_sta, hdr);
|
||||
|
||||
|
@ -2216,8 +2217,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
|
|||
sta->txrate_idx = i;
|
||||
|
||||
sta->last_txrate_idx = sta->txrate_idx;
|
||||
/* WTF is with this bogus comment? A doesn't have cck rates */
|
||||
/* For MODE_IEEE80211A, cck rates are at end of rate table */
|
||||
/* For MODE_IEEE80211A, skip over cck rates in global rate table */
|
||||
if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ)
|
||||
sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
|
||||
|
||||
|
|
|
@ -1273,7 +1273,7 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
|
|||
|
||||
if (src == IWL_PWR_SRC_VAUX) {
|
||||
u32 val;
|
||||
ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
|
||||
ret = pci_read_config_dword(priv->pci_dev, PCI_CFG_POWER_SOURCE,
|
||||
&val);
|
||||
|
||||
if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
|
||||
|
@ -2486,6 +2486,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
|||
if (!priv->vif || !priv->is_open)
|
||||
return;
|
||||
|
||||
iwl_power_cancel_timeout(priv);
|
||||
iwl_scan_cancel_timeout(priv, 200);
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
@ -2550,10 +2551,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Enable Rx differential gain and sensitivity calibrations */
|
||||
iwl_chain_noise_reset(priv);
|
||||
priv->start_calib = 1;
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
|
||||
priv->assoc_station_added = 1;
|
||||
|
||||
|
@ -2561,7 +2558,12 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
|
|||
iwl_activate_qos(priv, 0);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
iwl_power_update_mode(priv, 0);
|
||||
iwl_power_enable_management(priv);
|
||||
|
||||
/* Enable Rx differential gain and sensitivity calibrations */
|
||||
iwl_chain_noise_reset(priv);
|
||||
priv->start_calib = 1;
|
||||
|
||||
/* we have just associated, don't start scan too early */
|
||||
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
|
||||
}
|
||||
|
@ -2720,12 +2722,6 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
IWL_DEBUG_MACDUMP("enter\n");
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
|
||||
IWL_DEBUG_MAC80211("leave - monitor\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
|
||||
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
|
||||
|
||||
|
@ -2841,7 +2837,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
|
|||
)
|
||||
priv->staging_rxon.flags = 0;
|
||||
|
||||
iwl_set_rxon_channel(priv, conf->channel->band, channel);
|
||||
iwl_set_rxon_channel(priv, conf->channel);
|
||||
|
||||
iwl_set_flags_for_band(priv, conf->channel->band);
|
||||
|
||||
|
@ -3179,9 +3175,9 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
|
|||
|
||||
}
|
||||
|
||||
static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
|
||||
static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len)
|
||||
{
|
||||
int rc = 0;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct iwl_priv *priv = hw->priv;
|
||||
|
||||
|
@ -3191,41 +3187,40 @@ static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
|
|||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (!iwl_is_ready_rf(priv)) {
|
||||
rc = -EIO;
|
||||
ret = -EIO;
|
||||
IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
|
||||
rc = -EIO;
|
||||
ret = -EIO;
|
||||
IWL_ERROR("ERROR: APs don't scan\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* we don't schedule scan within next_scan_jiffies period */
|
||||
if (priv->next_scan_jiffies &&
|
||||
time_after(priv->next_scan_jiffies, jiffies)) {
|
||||
rc = -EAGAIN;
|
||||
time_after(priv->next_scan_jiffies, jiffies)) {
|
||||
IWL_DEBUG_SCAN("scan rejected: within next scan period\n");
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
/* if we just finished scan ask for delay */
|
||||
if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
|
||||
IWL_DELAY_NEXT_SCAN, jiffies)) {
|
||||
rc = -EAGAIN;
|
||||
if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
|
||||
time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
|
||||
IWL_DEBUG_SCAN("scan rejected: within previous scan period\n");
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (len) {
|
||||
IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
|
||||
iwl_escape_essid(ssid, len), (int)len);
|
||||
|
||||
if (ssid_len) {
|
||||
priv->one_direct_scan = 1;
|
||||
priv->direct_ssid_len = (u8)
|
||||
min((u8) len, (u8) IW_ESSID_MAX_SIZE);
|
||||
priv->direct_ssid_len = min_t(u8, ssid_len, IW_ESSID_MAX_SIZE);
|
||||
memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
|
||||
} else
|
||||
} else {
|
||||
priv->one_direct_scan = 0;
|
||||
}
|
||||
|
||||
rc = iwl_scan_initiate(priv);
|
||||
ret = iwl_scan_initiate(priv);
|
||||
|
||||
IWL_DEBUG_MAC80211("leave\n");
|
||||
|
||||
|
@ -3233,7 +3228,7 @@ out_unlock:
|
|||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
return rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
|
@ -3536,6 +3531,16 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
/* Per mac80211.h: This is only used in IBSS mode... */
|
||||
if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
|
||||
|
||||
/* switch to CAM during association period.
|
||||
* the ucode will block any association/authentication
|
||||
* frome during assiciation period if it can not hear
|
||||
* the AP because of PM. the timer enable PM back is
|
||||
* association do not complete
|
||||
*/
|
||||
if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
|
||||
IEEE80211_CHAN_RADAR))
|
||||
iwl_power_disable_management(priv, 3000);
|
||||
|
||||
IWL_DEBUG_MAC80211("leave - not in IBSS\n");
|
||||
mutex_unlock(&priv->mutex);
|
||||
return;
|
||||
|
@ -3620,11 +3625,11 @@ static ssize_t store_debug_level(struct device *d,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = d->driver_data;
|
||||
char *p = (char *)buf;
|
||||
u32 val;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
val = simple_strtoul(p, &p, 0);
|
||||
if (p == buf)
|
||||
ret = strict_strtoul(buf, 0, &val);
|
||||
if (ret)
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": %s is not in hex or decimal form.\n", buf);
|
||||
else
|
||||
|
@ -3696,11 +3701,11 @@ static ssize_t store_tx_power(struct device *d,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
|
||||
char *p = (char *)buf;
|
||||
u32 val;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
val = simple_strtoul(p, &p, 10);
|
||||
if (p == buf)
|
||||
ret = strict_strtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": %s is not in decimal form.\n", buf);
|
||||
else
|
||||
|
@ -3724,7 +3729,12 @@ static ssize_t store_flags(struct device *d,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
|
||||
u32 flags = simple_strtoul(buf, NULL, 0);
|
||||
unsigned long val;
|
||||
u32 flags;
|
||||
int ret = strict_strtoul(buf, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
flags = (u32)val;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
|
||||
|
@ -3732,8 +3742,7 @@ static ssize_t store_flags(struct device *d,
|
|||
if (iwl_scan_cancel_timeout(priv, 100))
|
||||
IWL_WARNING("Could not cancel scan.\n");
|
||||
else {
|
||||
IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
|
||||
flags);
|
||||
IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags);
|
||||
priv->staging_rxon.flags = cpu_to_le32(flags);
|
||||
iwl4965_commit_rxon(priv);
|
||||
}
|
||||
|
@ -3759,7 +3768,12 @@ static ssize_t store_filter_flags(struct device *d,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
|
||||
u32 filter_flags = simple_strtoul(buf, NULL, 0);
|
||||
unsigned long val;
|
||||
u32 filter_flags;
|
||||
int ret = strict_strtoul(buf, 0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
filter_flags = (u32)val;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
|
||||
|
@ -3860,10 +3874,12 @@ static ssize_t store_retry_rate(struct device *d,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
long val;
|
||||
int ret = strict_strtol(buf, 10, &val);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
priv->retry_rate = simple_strtoul(buf, NULL, 0);
|
||||
if (priv->retry_rate <= 0)
|
||||
priv->retry_rate = 1;
|
||||
priv->retry_rate = (val > 0) ? val : 1;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -3884,9 +3900,9 @@ static ssize_t store_power_level(struct device *d,
|
|||
{
|
||||
struct iwl_priv *priv = dev_get_drvdata(d);
|
||||
int ret;
|
||||
int mode;
|
||||
unsigned long mode;
|
||||
|
||||
|
||||
mode = simple_strtoul(buf, NULL, 0);
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (!iwl_is_ready(priv)) {
|
||||
|
@ -3894,6 +3910,10 @@ static ssize_t store_power_level(struct device *d,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = strict_strtoul(buf, 10, &mode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iwl_power_set_user_mode(priv, mode);
|
||||
if (ret) {
|
||||
IWL_DEBUG_MAC80211("failed setting power mode.\n");
|
||||
|
@ -4073,6 +4093,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
|||
/* FIXME : remove when resolved PENDING */
|
||||
INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
|
||||
iwl_setup_scan_deferred_work(priv);
|
||||
iwl_setup_power_deferred_work(priv);
|
||||
|
||||
if (priv->cfg->ops->lib->setup_deferred_work)
|
||||
priv->cfg->ops->lib->setup_deferred_work(priv);
|
||||
|
@ -4092,6 +4113,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
|||
|
||||
cancel_delayed_work_sync(&priv->init_alive_start);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
cancel_delayed_work_sync(&priv->set_power_save);
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
del_timer_sync(&priv->statistics_periodic);
|
||||
|
@ -4140,7 +4162,7 @@ static struct ieee80211_ops iwl4965_hw_ops = {
|
|||
.reset_tsf = iwl4965_mac_reset_tsf,
|
||||
.bss_info_changed = iwl4965_bss_info_changed,
|
||||
.ampdu_action = iwl4965_mac_ampdu_action,
|
||||
.hw_scan = iwl4965_mac_hw_scan
|
||||
.hw_scan = iwl_mac_hw_scan
|
||||
};
|
||||
|
||||
static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
@ -4215,9 +4237,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
/* We disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
* PCI Tx retries from interfering with C3 CPU state */
|
||||
pci_write_config_byte(pdev, 0x41, 0x00);
|
||||
|
||||
/***********************
|
||||
* 3. Read REV register
|
||||
|
@ -4237,6 +4256,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
": Detected Intel Wireless WiFi Link %s REV=0x%X\n",
|
||||
priv->cfg->name, priv->hw_rev);
|
||||
|
||||
/* We disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
* PCI Tx retries from interfering with C3 CPU state */
|
||||
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
|
||||
|
||||
/* amp init */
|
||||
err = priv->cfg->ops->lib->apm_ops.init(priv);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -66,6 +66,66 @@
|
|||
#include "iwl-core.h"
|
||||
#include "iwl-calib.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* INIT calibrations framework
|
||||
*****************************************************************************/
|
||||
|
||||
int iwl_send_calib_results(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = REPLY_PHY_CALIBRATION_CMD,
|
||||
.meta.flags = CMD_SIZE_HUGE,
|
||||
};
|
||||
|
||||
for (i = 0; i < IWL_CALIB_MAX; i++)
|
||||
if (priv->calib_results[i].buf) {
|
||||
hcmd.len = priv->calib_results[i].buf_len;
|
||||
hcmd.data = priv->calib_results[i].buf;
|
||||
ret = iwl_send_cmd_sync(priv, &hcmd);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
IWL_ERROR("Error %d iteration %d\n", ret, i);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_send_calib_results);
|
||||
|
||||
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)
|
||||
{
|
||||
if (res->buf_len != len) {
|
||||
kfree(res->buf);
|
||||
res->buf = kzalloc(len, GFP_ATOMIC);
|
||||
}
|
||||
if (unlikely(res->buf == NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
res->buf_len = len;
|
||||
memcpy(res->buf, buf, len);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_calib_set);
|
||||
|
||||
void iwl_calib_free_results(struct iwl_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IWL_CALIB_MAX; i++) {
|
||||
kfree(priv->calib_results[i].buf);
|
||||
priv->calib_results[i].buf = NULL;
|
||||
priv->calib_results[i].buf_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* RUNTIME calibrations framework
|
||||
*****************************************************************************/
|
||||
|
||||
/* "false alarms" are signals that our DSP tries to lock onto,
|
||||
* but then determines that they are either noise, or transmissions
|
||||
* from a distant wireless network (also "noise", really) that get
|
||||
|
|
|
@ -163,6 +163,13 @@ enum {
|
|||
/* iwl_cmd_header flags value */
|
||||
#define IWL_CMD_FAILED_MSK 0x40
|
||||
|
||||
#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f)
|
||||
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
|
||||
#define SEQ_TO_INDEX(s) ((s) & 0xff)
|
||||
#define INDEX_TO_SEQ(i) ((i) & 0xff)
|
||||
#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000)
|
||||
#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000)
|
||||
|
||||
/**
|
||||
* struct iwl_cmd_header
|
||||
*
|
||||
|
@ -171,7 +178,7 @@ enum {
|
|||
*/
|
||||
struct iwl_cmd_header {
|
||||
u8 cmd; /* Command ID: REPLY_RXON, etc. */
|
||||
u8 flags; /* IWL_CMD_* */
|
||||
u8 flags; /* 0:5 reserved, 6 abort, 7 internal */
|
||||
/*
|
||||
* The driver sets up the sequence number to values of its chosing.
|
||||
* uCode does not use this value, but passes it back to the driver
|
||||
|
@ -187,11 +194,12 @@ struct iwl_cmd_header {
|
|||
*
|
||||
* The Linux driver uses the following format:
|
||||
*
|
||||
* 0:7 index/position within Tx queue
|
||||
* 8:13 Tx queue selection
|
||||
* 14:14 driver sets this to indicate command is in the 'huge'
|
||||
* storage at the end of the command buffers, i.e. scan cmd
|
||||
* 15:15 uCode sets this in uCode-originated response/notification
|
||||
* 0:7 tfd index - position within TX queue
|
||||
* 8:12 TX queue id
|
||||
* 13 reserved
|
||||
* 14 huge - driver sets this to indicate command is in the
|
||||
* 'huge' storage at the end of the command buffers
|
||||
* 15 unsolicited RX or uCode-originated notification
|
||||
*/
|
||||
__le16 sequence;
|
||||
|
||||
|
@ -2026,8 +2034,8 @@ struct iwl4965_spectrum_notification {
|
|||
* bit 2 - '0' PM have to walk up every DTIM
|
||||
* '1' PM could sleep over DTIM till listen Interval.
|
||||
* PCI power managed
|
||||
* bit 3 - '0' (PCI_LINK_CTRL & 0x1)
|
||||
* '1' !(PCI_LINK_CTRL & 0x1)
|
||||
* bit 3 - '0' (PCI_CFG_LINK_CTRL & 0x1)
|
||||
* '1' !(PCI_CFG_LINK_CTRL & 0x1)
|
||||
* Force sleep Modes
|
||||
* bit 31/30- '00' use both mac/xtal sleeps
|
||||
* '01' force Mac sleep
|
||||
|
|
|
@ -773,7 +773,7 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
|
|||
EXPORT_SYMBOL(iwl_set_rxon_chain);
|
||||
|
||||
/**
|
||||
* iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON
|
||||
* iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
|
||||
* @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
|
||||
* @channel: Any channel valid for the requested phymode
|
||||
|
||||
|
@ -782,10 +782,11 @@ EXPORT_SYMBOL(iwl_set_rxon_chain);
|
|||
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
|
||||
* in the staging RXON flag structure based on the phymode
|
||||
*/
|
||||
int iwl_set_rxon_channel(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u16 channel)
|
||||
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
|
||||
{
|
||||
enum ieee80211_band band = ch->band;
|
||||
u16 channel = ieee80211_frequency_to_channel(ch->center_freq);
|
||||
|
||||
if (!iwl_get_channel_info(priv, band, channel)) {
|
||||
IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
|
||||
channel, band);
|
||||
|
@ -819,6 +820,10 @@ int iwl_setup_mac(struct iwl_priv *priv)
|
|||
/* Tell mac80211 our characteristics */
|
||||
hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
/* Default value; 4 EDCA QOS priorities */
|
||||
hw->queues = 4;
|
||||
/* queues to support 11n aggregation */
|
||||
|
@ -906,8 +911,6 @@ int iwl_init_drv(struct iwl_priv *priv)
|
|||
priv->qos_data.qos_active = 0;
|
||||
priv->qos_data.qos_cap.val = 0;
|
||||
|
||||
iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
|
||||
|
||||
priv->rates_mask = IWL_RATES_MASK;
|
||||
/* If power management is turned on, default to AC mode */
|
||||
priv->power_mode = IWL_POWER_AC;
|
||||
|
@ -934,22 +937,6 @@ err:
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_init_drv);
|
||||
|
||||
void iwl_free_calib_results(struct iwl_priv *priv)
|
||||
{
|
||||
kfree(priv->calib_results.lo_res);
|
||||
priv->calib_results.lo_res = NULL;
|
||||
priv->calib_results.lo_res_len = 0;
|
||||
|
||||
kfree(priv->calib_results.tx_iq_res);
|
||||
priv->calib_results.tx_iq_res = NULL;
|
||||
priv->calib_results.tx_iq_res_len = 0;
|
||||
|
||||
kfree(priv->calib_results.tx_iq_perd_res);
|
||||
priv->calib_results.tx_iq_perd_res = NULL;
|
||||
priv->calib_results.tx_iq_perd_res_len = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_free_calib_results);
|
||||
|
||||
int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -977,10 +964,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_set_tx_power);
|
||||
|
||||
|
||||
void iwl_uninit_drv(struct iwl_priv *priv)
|
||||
{
|
||||
iwl_free_calib_results(priv);
|
||||
iwl_calib_free_results(priv);
|
||||
iwlcore_free_geos(priv);
|
||||
iwl_free_channel_map(priv);
|
||||
kfree(priv->scan);
|
||||
|
|
|
@ -186,12 +186,9 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
|
|||
void iwl_hw_detect(struct iwl_priv *priv);
|
||||
|
||||
void iwl_clear_stations_table(struct iwl_priv *priv);
|
||||
void iwl_free_calib_results(struct iwl_priv *priv);
|
||||
void iwl_reset_qos(struct iwl_priv *priv);
|
||||
void iwl_set_rxon_chain(struct iwl_priv *priv);
|
||||
int iwl_set_rxon_channel(struct iwl_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u16 channel);
|
||||
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
|
||||
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
|
||||
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
|
||||
struct ieee80211_ht_info *sta_ht_inf);
|
||||
|
@ -291,6 +288,13 @@ int iwl_scan_initiate(struct iwl_priv *priv);
|
|||
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
|
||||
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
|
||||
|
||||
/*******************************************************************************
|
||||
* Calibrations - implemented in iwl-calib.c
|
||||
******************************************************************************/
|
||||
int iwl_send_calib_results(struct iwl_priv *priv);
|
||||
int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len);
|
||||
void iwl_calib_free_results(struct iwl_priv *priv);
|
||||
|
||||
/*****************************************************
|
||||
* S e n d i n g H o s t C o m m a n d s *
|
||||
*****************************************************/
|
||||
|
|
|
@ -225,12 +225,6 @@ struct iwl_frame {
|
|||
struct list_head list;
|
||||
};
|
||||
|
||||
#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf)
|
||||
#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8)
|
||||
#define SEQ_TO_INDEX(x) ((u8)(x & 0xff))
|
||||
#define INDEX_TO_SEQ(x) ((u8)(x & 0xff))
|
||||
#define SEQ_HUGE_FRAME (0x4000)
|
||||
#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000)
|
||||
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
|
||||
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
|
||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||
|
@ -637,12 +631,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
|
|||
|
||||
struct iwl_priv;
|
||||
|
||||
/*
|
||||
* Forward declare iwl-4965.c functions for iwl-base.c
|
||||
*/
|
||||
extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
|
||||
int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
|
||||
u8 tid, int txq_id);
|
||||
|
||||
/* Structures, enum, and defines specific to the 4965 */
|
||||
|
||||
|
@ -734,13 +722,10 @@ struct statistics_general_data {
|
|||
u32 beacon_energy_c;
|
||||
};
|
||||
|
||||
struct iwl_calib_results {
|
||||
void *tx_iq_res;
|
||||
void *tx_iq_perd_res;
|
||||
void *lo_res;
|
||||
u32 tx_iq_res_len;
|
||||
u32 tx_iq_perd_res_len;
|
||||
u32 lo_res_len;
|
||||
/* Opaque calibration results */
|
||||
struct iwl_calib_result {
|
||||
void *buf;
|
||||
size_t buf_len;
|
||||
};
|
||||
|
||||
enum ucode_type {
|
||||
|
@ -802,6 +787,7 @@ enum {
|
|||
|
||||
|
||||
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
|
||||
#define IWL_CALIB_MAX 3
|
||||
|
||||
struct iwl_priv {
|
||||
|
||||
|
@ -845,7 +831,7 @@ struct iwl_priv {
|
|||
s32 last_temperature;
|
||||
|
||||
/* init calibration results */
|
||||
struct iwl_calib_results calib_results;
|
||||
struct iwl_calib_result calib_results[IWL_CALIB_MAX];
|
||||
|
||||
/* Scan related variables */
|
||||
unsigned long last_scan_jiffies;
|
||||
|
@ -1032,6 +1018,7 @@ struct iwl_priv {
|
|||
|
||||
struct tasklet_struct irq_tasklet;
|
||||
|
||||
struct delayed_work set_power_save;
|
||||
struct delayed_work init_alive_start;
|
||||
struct delayed_work alive_start;
|
||||
struct delayed_work scan_check;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define _iwl_write32(priv, ofs, val) writel((val), (priv)->hw_base + (ofs))
|
||||
#define _iwl_write32(priv, ofs, val) iowrite32((val), (priv)->hw_base + (ofs))
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
|
||||
u32 ofs, u32 val)
|
||||
|
@ -75,7 +75,7 @@ static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
|
|||
#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
|
||||
#endif
|
||||
|
||||
#define _iwl_read32(priv, ofs) readl((priv)->hw_base + (ofs))
|
||||
#define _iwl_read32(priv, ofs) ioread32((priv)->hw_base + (ofs))
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
|
||||
{
|
||||
|
@ -155,28 +155,10 @@ static inline void __iwl_clear_bit(const char *f, u32 l,
|
|||
static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 gp_ctl;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (atomic_read(&priv->restrict_refcnt))
|
||||
return 0;
|
||||
#endif
|
||||
if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
|
||||
test_bit(STATUS_RF_KILL_SW, &priv->status)) {
|
||||
IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
|
||||
"wakes up NIC\n");
|
||||
|
||||
/* 10 msec allows time for NIC to complete its data save */
|
||||
gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
|
||||
if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
|
||||
IWL_DEBUG_RF_KILL("Wait for complete power-down, "
|
||||
"gpctl = 0x%08x\n", gp_ctl);
|
||||
mdelay(10);
|
||||
} else
|
||||
IWL_DEBUG_RF_KILL("power-down complete, "
|
||||
"gpctl = 0x%08x\n", gp_ctl);
|
||||
}
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
|
||||
|
|
|
@ -152,9 +152,10 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
|
|||
/* initialize to default */
|
||||
static int iwl_power_init_handle(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0, i;
|
||||
struct iwl_power_mgr *pow_data;
|
||||
int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
|
||||
struct iwl_powertable_cmd *cmd;
|
||||
int i;
|
||||
u16 pci_pm;
|
||||
|
||||
IWL_DEBUG_POWER("Initialize power \n");
|
||||
|
@ -167,25 +168,19 @@ static int iwl_power_init_handle(struct iwl_priv *priv)
|
|||
memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
|
||||
memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
|
||||
|
||||
ret = pci_read_config_word(priv->pci_dev,
|
||||
PCI_LINK_CTRL, &pci_pm);
|
||||
if (ret != 0)
|
||||
return 0;
|
||||
else {
|
||||
struct iwl_powertable_cmd *cmd;
|
||||
pci_read_config_word(priv->pci_dev, PCI_CFG_LINK_CTRL, &pci_pm);
|
||||
|
||||
IWL_DEBUG_POWER("adjust power command flags\n");
|
||||
IWL_DEBUG_POWER("adjust power command flags\n");
|
||||
|
||||
for (i = 0; i < IWL_POWER_MAX; i++) {
|
||||
cmd = &pow_data->pwr_range_0[i].cmd;
|
||||
for (i = 0; i < IWL_POWER_MAX; i++) {
|
||||
cmd = &pow_data->pwr_range_0[i].cmd;
|
||||
|
||||
if (pci_pm & 0x1)
|
||||
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
|
||||
else
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
}
|
||||
if (pci_pm & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
|
||||
cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
|
||||
else
|
||||
cmd->flags |= IWL_POWER_PCI_PM_MSK;
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* adjust power command according to dtim period and power level*/
|
||||
|
@ -324,7 +319,7 @@ EXPORT_SYMBOL(iwl_power_update_mode);
|
|||
* this will be usefull for rate scale to disable PM during heavy
|
||||
* Tx/Rx activities
|
||||
*/
|
||||
int iwl_power_disable_management(struct iwl_priv *priv)
|
||||
int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
|
||||
{
|
||||
u16 prev_mode;
|
||||
int ret = 0;
|
||||
|
@ -337,6 +332,11 @@ int iwl_power_disable_management(struct iwl_priv *priv)
|
|||
ret = iwl_power_update_mode(priv, 0);
|
||||
priv->power_data.power_disabled = 1;
|
||||
priv->power_data.user_power_setting = prev_mode;
|
||||
cancel_delayed_work(&priv->set_power_save);
|
||||
if (ms)
|
||||
queue_delayed_work(priv->workqueue, &priv->set_power_save,
|
||||
msecs_to_jiffies(ms));
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -431,3 +431,35 @@ int iwl_power_temperature_change(struct iwl_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_power_temperature_change);
|
||||
|
||||
static void iwl_bg_set_power_save(struct work_struct *work)
|
||||
{
|
||||
struct iwl_priv *priv = container_of(work,
|
||||
struct iwl_priv, set_power_save.work);
|
||||
IWL_DEBUG(IWL_DL_STATE, "update power\n");
|
||||
|
||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
/* on starting association we disable power managment
|
||||
* until association, if association failed then this
|
||||
* timer will expire and enable PM again.
|
||||
*/
|
||||
if (!iwl_is_associated(priv))
|
||||
iwl_power_enable_management(priv);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
void iwl_setup_power_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_setup_power_deferred_work);
|
||||
|
||||
void iwl_power_cancel_timeout(struct iwl_priv *priv)
|
||||
{
|
||||
cancel_delayed_work(&priv->set_power_save);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_power_cancel_timeout);
|
||||
|
|
|
@ -78,8 +78,10 @@ struct iwl_power_mgr {
|
|||
u8 power_disabled; /* flag to disable using power saving level */
|
||||
};
|
||||
|
||||
void iwl_setup_power_deferred_work(struct iwl_priv *priv);
|
||||
void iwl_power_cancel_timeout(struct iwl_priv *priv);
|
||||
int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh);
|
||||
int iwl_power_disable_management(struct iwl_priv *priv);
|
||||
int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
|
||||
int iwl_power_enable_management(struct iwl_priv *priv);
|
||||
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
|
||||
int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);
|
||||
|
|
|
@ -968,6 +968,11 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|||
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
/* If we are in monitor mode, use BCAST. This is required for
|
||||
* packet injection. */
|
||||
case IEEE80211_IF_TYPE_MNTR:
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
||||
default:
|
||||
IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode);
|
||||
return priv->hw_params.bcast_sta_id;
|
||||
|
|
|
@ -789,11 +789,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
goto drop_unlock;
|
||||
}
|
||||
|
||||
if (!priv->vif) {
|
||||
IWL_DEBUG_DROP("Dropping - !priv->vif\n");
|
||||
goto drop_unlock;
|
||||
}
|
||||
|
||||
if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
|
||||
IWL_INVALID_RATE) {
|
||||
IWL_ERROR("ERROR: No TX rate available.\n");
|
||||
|
@ -815,9 +810,11 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||
|
||||
/* drop all data frame if we are not associated */
|
||||
if (ieee80211_is_data(fc) &&
|
||||
(!iwl_is_associated(priv) ||
|
||||
((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
|
||||
!priv->assoc_station_added)) {
|
||||
(priv->iw_mode != IEEE80211_IF_TYPE_MNTR ||
|
||||
!(info->flags & IEEE80211_TX_CTL_INJECTED)) && /* packet injection */
|
||||
(!iwl_is_associated(priv) ||
|
||||
((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
|
||||
!priv->assoc_station_added)) {
|
||||
IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
|
||||
goto drop_unlock;
|
||||
}
|
||||
|
@ -1057,7 +1054,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
|
||||
INDEX_TO_SEQ(q->write_ptr));
|
||||
if (out_cmd->meta.flags & CMD_SIZE_HUGE)
|
||||
out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
|
||||
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
|
||||
len = (idx == TFD_CMD_SLOTS) ?
|
||||
IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
|
||||
phys_addr = pci_map_single(priv->pci_dev, out_cmd, len,
|
||||
|
@ -1192,8 +1189,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
|
|||
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
|
||||
int txq_id = SEQ_TO_QUEUE(sequence);
|
||||
int index = SEQ_TO_INDEX(sequence);
|
||||
int huge = sequence & SEQ_HUGE_FRAME;
|
||||
int cmd_index;
|
||||
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
|
||||
struct iwl_cmd *cmd;
|
||||
|
||||
/* If a Tx command is being handled and it isn't in the actual
|
||||
|
|
|
@ -4782,8 +4782,11 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
|
|||
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
|
||||
* sending probe req. This should be set long enough to hear probe responses
|
||||
* from more than one AP. */
|
||||
#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
|
||||
#define IWL_ACTIVE_DWELL_TIME_52 (10)
|
||||
#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
|
||||
#define IWL_ACTIVE_DWELL_TIME_52 (20)
|
||||
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
|
||||
#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
|
||||
|
||||
/* For faster active scanning, scan will move to the next channel if fewer than
|
||||
* PLCP_QUIET_THRESH packets are heard on this channel within
|
||||
|
@ -4792,7 +4795,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
|
|||
* no other traffic).
|
||||
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
|
||||
#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
|
||||
#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
|
||||
#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */
|
||||
|
||||
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
|
||||
* Must be set longer than active dwell time.
|
||||
|
@ -4802,19 +4805,23 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
|
|||
#define IWL_PASSIVE_DWELL_BASE (100)
|
||||
#define IWL_CHANNEL_TUNE_TIME 5
|
||||
|
||||
#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
|
||||
|
||||
static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
enum ieee80211_band band,
|
||||
u8 n_probes)
|
||||
{
|
||||
if (band == IEEE80211_BAND_5GHZ)
|
||||
return IWL_ACTIVE_DWELL_TIME_52;
|
||||
return IWL_ACTIVE_DWELL_TIME_52 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
|
||||
else
|
||||
return IWL_ACTIVE_DWELL_TIME_24;
|
||||
return IWL_ACTIVE_DWELL_TIME_24 +
|
||||
IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
|
||||
}
|
||||
|
||||
static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
u16 active = iwl3945_get_active_dwell_time(priv, band);
|
||||
u16 passive = (band == IEEE80211_BAND_2GHZ) ?
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
|
||||
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
|
||||
|
@ -4829,15 +4836,12 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv,
|
|||
passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
|
||||
}
|
||||
|
||||
if (passive <= active)
|
||||
passive = active + 1;
|
||||
|
||||
return passive;
|
||||
}
|
||||
|
||||
static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
|
||||
enum ieee80211_band band,
|
||||
u8 is_active, u8 direct_mask,
|
||||
u8 is_active, u8 n_probes,
|
||||
struct iwl3945_scan_channel *scan_ch)
|
||||
{
|
||||
const struct ieee80211_channel *channels = NULL;
|
||||
|
@ -4853,9 +4857,12 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
|
|||
|
||||
channels = sband->channels;
|
||||
|
||||
active_dwell = iwl3945_get_active_dwell_time(priv, band);
|
||||
active_dwell = iwl3945_get_active_dwell_time(priv, band, n_probes);
|
||||
passive_dwell = iwl3945_get_passive_dwell_time(priv, band);
|
||||
|
||||
if (passive_dwell <= active_dwell)
|
||||
passive_dwell = active_dwell + 1;
|
||||
|
||||
for (i = 0, added = 0; i < sband->n_channels; i++) {
|
||||
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
|
||||
continue;
|
||||
|
@ -4875,8 +4882,8 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
|
|||
else
|
||||
scan_ch->type = 1; /* active */
|
||||
|
||||
if (scan_ch->type & 1)
|
||||
scan_ch->type |= (direct_mask << 1);
|
||||
if ((scan_ch->type & 1) && n_probes)
|
||||
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
|
||||
|
||||
scan_ch->active_dwell = cpu_to_le16(active_dwell);
|
||||
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
|
||||
|
@ -6093,7 +6100,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
|
|||
int rc = 0;
|
||||
struct iwl3945_scan_cmd *scan;
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
u8 direct_mask;
|
||||
u8 n_probes = 2;
|
||||
enum ieee80211_band band;
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
@ -6201,7 +6208,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
|
|||
scan->direct_scan[0].len = priv->direct_ssid_len;
|
||||
memcpy(scan->direct_scan[0].ssid,
|
||||
priv->direct_ssid, priv->direct_ssid_len);
|
||||
direct_mask = 1;
|
||||
n_probes++;
|
||||
} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
|
||||
IWL_DEBUG_SCAN
|
||||
("Kicking off one direct scan for '%s' when not associated\n",
|
||||
|
@ -6209,11 +6216,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
|
|||
scan->direct_scan[0].id = WLAN_EID_SSID;
|
||||
scan->direct_scan[0].len = priv->essid_len;
|
||||
memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
|
||||
direct_mask = 1;
|
||||
} else {
|
||||
n_probes++;
|
||||
} else
|
||||
IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
|
||||
direct_mask = 0;
|
||||
}
|
||||
|
||||
/* We don't build a direct scan probe request; the uCode will do
|
||||
* that based on the direct_mask added to each channel entry */
|
||||
|
@ -6246,18 +6251,10 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
|
|||
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
|
||||
scan->filter_flags = RXON_FILTER_PROMISC_MSK;
|
||||
|
||||
if (direct_mask)
|
||||
scan->channel_count =
|
||||
iwl3945_get_channels_for_scan(
|
||||
priv, band, 1, /* active */
|
||||
direct_mask,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
else
|
||||
scan->channel_count =
|
||||
iwl3945_get_channels_for_scan(
|
||||
priv, band, 0, /* passive */
|
||||
direct_mask,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
scan->channel_count =
|
||||
iwl3945_get_channels_for_scan(priv, band, 1, /* active */
|
||||
n_probes,
|
||||
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
|
||||
|
||||
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
|
||||
scan->channel_count * sizeof(struct iwl3945_scan_channel);
|
||||
|
@ -6320,11 +6317,8 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
|
|||
|
||||
#define IWL_DELAY_NEXT_SCAN (HZ*2)
|
||||
|
||||
static void iwl3945_bg_post_associate(struct work_struct *data)
|
||||
static void iwl3945_post_associate(struct iwl3945_priv *priv)
|
||||
{
|
||||
struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv,
|
||||
post_associate.work);
|
||||
|
||||
int rc = 0;
|
||||
struct ieee80211_conf *conf = NULL;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
@ -6342,12 +6336,9 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
|
|||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||
return;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
if (!priv->vif || !priv->is_open) {
|
||||
mutex_unlock(&priv->mutex);
|
||||
if (!priv->vif || !priv->is_open)
|
||||
return;
|
||||
}
|
||||
|
||||
iwl3945_scan_cancel_timeout(priv, 200);
|
||||
|
||||
conf = ieee80211_get_hw_conf(priv->hw);
|
||||
|
@ -6419,7 +6410,6 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
|
|||
|
||||
/* we have just associated, don't start scan too early */
|
||||
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
static void iwl3945_bg_abort_scan(struct work_struct *work)
|
||||
|
@ -6567,7 +6557,6 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
|
|||
*/
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl3945_scan_cancel_timeout(priv, 100);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
mutex_unlock(&priv->mutex);
|
||||
}
|
||||
|
||||
|
@ -6933,7 +6922,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
|
||||
if (iwl3945_is_ready_rf(priv)) {
|
||||
iwl3945_scan_cancel_timeout(priv, 100);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
|
||||
iwl3945_commit_rxon(priv);
|
||||
}
|
||||
|
@ -6948,6 +6936,63 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
IWL_DEBUG_MAC80211("leave\n");
|
||||
}
|
||||
|
||||
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
|
||||
|
||||
static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changes)
|
||||
{
|
||||
struct iwl3945_priv *priv = hw->priv;
|
||||
|
||||
IWL_DEBUG_MAC80211("changes = 0x%X\n", changes);
|
||||
|
||||
if (changes & BSS_CHANGED_ERP_PREAMBLE) {
|
||||
IWL_DEBUG_MAC80211("ERP_PREAMBLE %d\n",
|
||||
bss_conf->use_short_preamble);
|
||||
if (bss_conf->use_short_preamble)
|
||||
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
else
|
||||
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
|
||||
}
|
||||
|
||||
if (changes & BSS_CHANGED_ERP_CTS_PROT) {
|
||||
IWL_DEBUG_MAC80211("ERP_CTS %d\n", bss_conf->use_cts_prot);
|
||||
if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
|
||||
priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
|
||||
else
|
||||
priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
|
||||
}
|
||||
|
||||
if (changes & BSS_CHANGED_ASSOC) {
|
||||
IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
|
||||
/* This should never happen as this function should
|
||||
* never be called from interrupt context. */
|
||||
if (WARN_ON_ONCE(in_interrupt()))
|
||||
return;
|
||||
if (bss_conf->assoc) {
|
||||
priv->assoc_id = bss_conf->aid;
|
||||
priv->beacon_int = bss_conf->beacon_int;
|
||||
priv->timestamp0 = bss_conf->timestamp & 0xFFFFFFFF;
|
||||
priv->timestamp1 = (bss_conf->timestamp >> 32) &
|
||||
0xFFFFFFFF;
|
||||
priv->assoc_capability = bss_conf->assoc_capability;
|
||||
priv->next_scan_jiffies = jiffies +
|
||||
IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
|
||||
mutex_lock(&priv->mutex);
|
||||
iwl3945_post_associate(priv);
|
||||
mutex_unlock(&priv->mutex);
|
||||
} else {
|
||||
priv->assoc_id = 0;
|
||||
IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
|
||||
}
|
||||
} else if (changes && iwl3945_is_associated(priv) && priv->assoc_id) {
|
||||
IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
|
||||
iwl3945_send_rxon_assoc(priv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -7180,8 +7225,6 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
|
|||
|
||||
iwl3945_reset_qos(priv);
|
||||
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->assoc_id = 0;
|
||||
priv->assoc_capability = 0;
|
||||
|
@ -7266,7 +7309,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
|
|||
|
||||
iwl3945_reset_qos(priv);
|
||||
|
||||
queue_work(priv->workqueue, &priv->post_associate.work);
|
||||
iwl3945_post_associate(priv);
|
||||
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
||||
|
@ -7765,7 +7808,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
|
|||
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
|
||||
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
|
||||
INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
|
||||
INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
|
||||
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
|
||||
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
|
||||
INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
|
||||
|
@ -7783,7 +7825,6 @@ static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv)
|
|||
cancel_delayed_work_sync(&priv->init_alive_start);
|
||||
cancel_delayed_work(&priv->scan_check);
|
||||
cancel_delayed_work(&priv->alive_start);
|
||||
cancel_delayed_work(&priv->post_associate);
|
||||
cancel_work_sync(&priv->beacon_update);
|
||||
}
|
||||
|
||||
|
@ -7828,6 +7869,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
|
|||
.conf_tx = iwl3945_mac_conf_tx,
|
||||
.get_tsf = iwl3945_mac_get_tsf,
|
||||
.reset_tsf = iwl3945_mac_reset_tsf,
|
||||
.bss_info_changed = iwl3945_bss_info_changed,
|
||||
.hw_scan = iwl3945_mac_hw_scan
|
||||
};
|
||||
|
||||
|
@ -7888,6 +7930,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
|
|||
hw->flags = IEEE80211_HW_SIGNAL_DBM |
|
||||
IEEE80211_HW_NOISE_DBM;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
/* 4 EDCA QOS priorities */
|
||||
hw->queues = 4;
|
||||
|
||||
|
|
|
@ -447,6 +447,9 @@ static int __init init_mac80211_hwsim(void)
|
|||
|
||||
hw->channel_change_time = 1;
|
||||
hw->queues = 4;
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
hw->ampdu_queues = 1;
|
||||
|
||||
memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
|
||||
|
|
|
@ -19,13 +19,24 @@ enum control_frame_types {
|
|||
P54_CONTROL_TYPE_CHANNEL_CHANGE,
|
||||
P54_CONTROL_TYPE_FREQDONE,
|
||||
P54_CONTROL_TYPE_DCFINIT,
|
||||
P54_CONTROL_TYPE_FREEQUEUE = 7,
|
||||
P54_CONTROL_TYPE_ENCRYPTION,
|
||||
P54_CONTROL_TYPE_TIM,
|
||||
P54_CONTROL_TYPE_POWERMGT,
|
||||
P54_CONTROL_TYPE_FREEQUEUE,
|
||||
P54_CONTROL_TYPE_TXDONE,
|
||||
P54_CONTROL_TYPE_PING,
|
||||
P54_CONTROL_TYPE_STAT_READBACK,
|
||||
P54_CONTROL_TYPE_BBP,
|
||||
P54_CONTROL_TYPE_EEPROM_READBACK,
|
||||
P54_CONTROL_TYPE_LED
|
||||
P54_CONTROL_TYPE_LED,
|
||||
P54_CONTROL_TYPE_GPIO,
|
||||
P54_CONTROL_TYPE_TIMER,
|
||||
P54_CONTROL_TYPE_MODULATION,
|
||||
P54_CONTROL_TYPE_SYNTH_CONFIG,
|
||||
P54_CONTROL_TYPE_DETECTOR_VALUE,
|
||||
P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
|
||||
P54_CONTROL_TYPE_CCE_QUIET,
|
||||
P54_CONTROL_TYPE_PSM_STA_UNLOCK,
|
||||
};
|
||||
|
||||
struct p54_control_hdr {
|
||||
|
@ -38,11 +49,15 @@ struct p54_control_hdr {
|
|||
u8 data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
|
||||
#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )
|
||||
#define EEPROM_READBACK_LEN 0x3fc
|
||||
|
||||
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
|
||||
|
||||
#define FW_FMAC 0x464d4143
|
||||
#define FW_LM86 0x4c4d3836
|
||||
#define FW_LM87 0x4c4d3837
|
||||
#define FW_LM20 0x4c4d3230
|
||||
|
||||
struct p54_common {
|
||||
u32 rx_start;
|
||||
u32 rx_end;
|
||||
|
@ -53,26 +68,33 @@ struct p54_common {
|
|||
void (*stop)(struct ieee80211_hw *dev);
|
||||
int mode;
|
||||
u16 seqno;
|
||||
u16 rx_mtu;
|
||||
u8 headroom;
|
||||
u8 tailroom;
|
||||
struct mutex conf_mutex;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 bssid[ETH_ALEN];
|
||||
__le16 filter_type;
|
||||
struct pda_iq_autocal_entry *iq_autocal;
|
||||
unsigned int iq_autocal_len;
|
||||
struct pda_channel_output_limit *output_limit;
|
||||
unsigned int output_limit_len;
|
||||
struct pda_pa_curve_data *curve_data;
|
||||
__le16 rxhw;
|
||||
u16 rxhw;
|
||||
u8 version;
|
||||
u8 rx_antenna;
|
||||
unsigned int tx_hdr_len;
|
||||
void *cached_vdcf;
|
||||
unsigned int fw_var;
|
||||
unsigned int fw_interface;
|
||||
struct ieee80211_tx_queue_stats tx_stats[8];
|
||||
void *eeprom;
|
||||
struct completion eeprom_comp;
|
||||
};
|
||||
|
||||
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
|
||||
void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
|
||||
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
|
||||
void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
|
||||
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
|
||||
int p54_read_eeprom(struct ieee80211_hw *dev);
|
||||
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
|
||||
void p54_free_common(struct ieee80211_hw *dev);
|
||||
|
||||
|
|
|
@ -66,8 +66,7 @@ static struct ieee80211_supported_band band_2GHz = {
|
|||
.n_bitrates = ARRAY_SIZE(p54_rates),
|
||||
};
|
||||
|
||||
|
||||
void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
||||
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct bootrec_exp_if *exp_if;
|
||||
|
@ -79,7 +78,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
|||
int i;
|
||||
|
||||
if (priv->rx_start)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
while (data < end_data && *data)
|
||||
data++;
|
||||
|
@ -94,7 +93,8 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
|||
u32 code = le32_to_cpu(bootrec->code);
|
||||
switch (code) {
|
||||
case BR_CODE_COMPONENT_ID:
|
||||
switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
|
||||
priv->fw_interface = be32_to_cpup(bootrec->data);
|
||||
switch (priv->fw_interface) {
|
||||
case FW_FMAC:
|
||||
printk(KERN_INFO "p54: FreeMAC firmware\n");
|
||||
break;
|
||||
|
@ -105,7 +105,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
|||
printk(KERN_INFO "p54: LM86 firmware\n");
|
||||
break;
|
||||
case FW_LM87:
|
||||
printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
|
||||
printk(KERN_INFO "p54: LM87 firmware\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "p54: unknown firmware\n");
|
||||
|
@ -117,11 +117,22 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
|||
if (strnlen((unsigned char*)bootrec->data, 24) < 24)
|
||||
fw_version = (unsigned char*)bootrec->data;
|
||||
break;
|
||||
case BR_CODE_DESCR:
|
||||
priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]);
|
||||
case BR_CODE_DESCR: {
|
||||
struct bootrec_desc *desc =
|
||||
(struct bootrec_desc *)bootrec->data;
|
||||
priv->rx_start = le32_to_cpu(desc->rx_start);
|
||||
/* FIXME add sanity checking */
|
||||
priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500;
|
||||
priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
|
||||
priv->headroom = desc->headroom;
|
||||
priv->tailroom = desc->tailroom;
|
||||
if (bootrec->len == 11)
|
||||
priv->rx_mtu = (size_t) le16_to_cpu(
|
||||
(__le16)bootrec->data[10]);
|
||||
else
|
||||
priv->rx_mtu = (size_t)
|
||||
0x620 - priv->tx_hdr_len;
|
||||
break;
|
||||
}
|
||||
case BR_CODE_EXPOSED_IF:
|
||||
exp_if = (struct bootrec_exp_if *) bootrec->data;
|
||||
for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
|
||||
|
@ -152,6 +163,8 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
|
|||
priv->tx_stats[7].limit = 1;
|
||||
dev->queues = 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(p54_parse_firmware);
|
||||
|
||||
|
@ -237,6 +250,9 @@ static int p54_convert_rev1(struct ieee80211_hw *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char* p54_rf_chips[] = { "NULL", "Indigo?", "Duette",
|
||||
"Frisbee", "Xbow", "Longbow" };
|
||||
|
||||
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
|
@ -246,6 +262,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
void *tmp;
|
||||
int err;
|
||||
u8 *end = (u8 *)eeprom + len;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
wrap = (struct eeprom_pda_wrap *) eeprom;
|
||||
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
||||
|
@ -327,7 +344,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
while ((u8 *)tmp < entry->data + data_len) {
|
||||
struct bootrec_exp_if *exp_if = tmp;
|
||||
if (le16_to_cpu(exp_if->if_id) == 0xF)
|
||||
priv->rxhw = exp_if->variant & cpu_to_le16(0x07);
|
||||
priv->rxhw = le16_to_cpu(exp_if->variant) & 0x07;
|
||||
tmp += sizeof(struct bootrec_exp_if);
|
||||
}
|
||||
break;
|
||||
|
@ -353,6 +370,37 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
goto err;
|
||||
}
|
||||
|
||||
switch (priv->rxhw) {
|
||||
case 4: /* XBow */
|
||||
case 1: /* Indigo? */
|
||||
case 2: /* Duette */
|
||||
/* TODO: 5GHz initialization goes here */
|
||||
|
||||
case 3: /* Frisbee */
|
||||
case 5: /* Longbow */
|
||||
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: unsupported RF-Chip\n",
|
||||
wiphy_name(dev->wiphy));
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
|
||||
wiphy_name(dev->wiphy));
|
||||
random_ether_addr(perm_addr);
|
||||
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n",
|
||||
wiphy_name(dev->wiphy),
|
||||
print_mac(mac, dev->wiphy->perm_addr),
|
||||
priv->version, p54_rf_chips[priv->rxhw]);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -376,25 +424,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(p54_parse_eeprom);
|
||||
|
||||
void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
|
||||
{
|
||||
struct p54_eeprom_lm86 *eeprom_hdr;
|
||||
|
||||
hdr->magic1 = cpu_to_le16(0x8000);
|
||||
hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000);
|
||||
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
|
||||
hdr->retry1 = hdr->retry2 = 0;
|
||||
eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
|
||||
eeprom_hdr->offset = 0x0;
|
||||
eeprom_hdr->len = cpu_to_le16(0x2000);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
|
||||
|
||||
static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
|
||||
struct ieee80211_rx_status rx_status = {0};
|
||||
u16 freq = le16_to_cpu(hdr->freq);
|
||||
size_t header_len = sizeof(*hdr);
|
||||
|
||||
rx_status.signal = hdr->rssi;
|
||||
/* XX correct? */
|
||||
|
@ -406,10 +441,15 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
rx_status.mactime = le64_to_cpu(hdr->timestamp);
|
||||
rx_status.flag |= RX_FLAG_TSFT;
|
||||
|
||||
skb_pull(skb, sizeof(*hdr));
|
||||
if (hdr->magic & cpu_to_le16(0x4000))
|
||||
header_len += hdr->align[0];
|
||||
|
||||
skb_pull(skb, header_len);
|
||||
skb_trim(skb, le16_to_cpu(hdr->len));
|
||||
|
||||
ieee80211_rx_irqsafe(dev, skb, &rx_status);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
|
||||
|
@ -428,7 +468,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
||||
struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
|
||||
struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
|
||||
u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
|
||||
u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
|
||||
struct memrecord *range = NULL;
|
||||
u32 freed = 0;
|
||||
u32 last_addr = priv->rx_start;
|
||||
|
@ -487,7 +527,22 @@ out:
|
|||
p54_wake_free_queues(dev);
|
||||
}
|
||||
|
||||
static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
||||
struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
|
||||
struct p54_common *priv = dev->priv;
|
||||
|
||||
if (!priv->eeprom)
|
||||
return ;
|
||||
|
||||
memcpy(priv->eeprom, eeprom->data, eeprom->len);
|
||||
|
||||
complete(&priv->eeprom_comp);
|
||||
}
|
||||
|
||||
static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
|
||||
|
||||
|
@ -497,36 +552,27 @@ static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
break;
|
||||
case P54_CONTROL_TYPE_BBP:
|
||||
break;
|
||||
case P54_CONTROL_TYPE_EEPROM_READBACK:
|
||||
p54_rx_eeprom_readback(dev, skb);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
|
||||
wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns zero if skb can be reused */
|
||||
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
|
||||
switch (type) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
p54_rx_data(dev, skb);
|
||||
return -1;
|
||||
case 0x4d:
|
||||
/* TODO: do something better... but then again, I've never seen this happen */
|
||||
printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
|
||||
wiphy_name(dev->wiphy));
|
||||
break;
|
||||
case 0x80:
|
||||
p54_rx_control(dev, skb);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
|
||||
wiphy_name(dev->wiphy), type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (type == 0x80)
|
||||
return p54_rx_control(dev, skb);
|
||||
else
|
||||
return p54_rx_data(dev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(p54_rx);
|
||||
|
||||
|
@ -550,7 +596,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
|
|||
u32 target_addr = priv->rx_start;
|
||||
unsigned long flags;
|
||||
unsigned int left;
|
||||
len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
|
||||
len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
|
||||
|
||||
spin_lock_irqsave(&priv->tx_queue.lock, flags);
|
||||
left = skb_queue_len(&priv->tx_queue);
|
||||
|
@ -585,15 +631,74 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
|
|||
range->start_addr = target_addr;
|
||||
range->end_addr = target_addr + len;
|
||||
__skb_queue_after(&priv->tx_queue, target_skb, skb);
|
||||
if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
|
||||
if (largest_hole < priv->rx_mtu + priv->headroom +
|
||||
priv->tailroom +
|
||||
sizeof(struct p54_control_hdr))
|
||||
ieee80211_stop_queues(dev);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
|
||||
|
||||
data->req_id = cpu_to_le32(target_addr + 0x70);
|
||||
data->req_id = cpu_to_le32(target_addr + priv->headroom);
|
||||
}
|
||||
|
||||
int p54_read_eeprom(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct p54_control_hdr *hdr = NULL;
|
||||
struct p54_eeprom_lm86 *eeprom_hdr;
|
||||
size_t eeprom_size = 0x2020, offset = 0, blocksize;
|
||||
int ret = -ENOMEM;
|
||||
void *eeprom = NULL;
|
||||
|
||||
hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) +
|
||||
sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL);
|
||||
if (!hdr)
|
||||
goto free;
|
||||
|
||||
priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
|
||||
if (!priv->eeprom)
|
||||
goto free;
|
||||
|
||||
eeprom = kzalloc(eeprom_size, GFP_KERNEL);
|
||||
if (!eeprom)
|
||||
goto free;
|
||||
|
||||
hdr->magic1 = cpu_to_le16(0x8000);
|
||||
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
|
||||
hdr->retry1 = hdr->retry2 = 0;
|
||||
eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
|
||||
|
||||
while (eeprom_size) {
|
||||
blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN);
|
||||
hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr));
|
||||
eeprom_hdr->offset = cpu_to_le16(offset);
|
||||
eeprom_hdr->len = cpu_to_le16(blocksize);
|
||||
p54_assign_address(dev, NULL, hdr, hdr->len + sizeof(*hdr));
|
||||
priv->tx(dev, hdr, hdr->len + sizeof(*hdr), 0);
|
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
|
||||
printk(KERN_ERR "%s: device does not respond!\n",
|
||||
wiphy_name(dev->wiphy));
|
||||
ret = -EBUSY;
|
||||
goto free;
|
||||
}
|
||||
|
||||
memcpy(eeprom + offset, priv->eeprom, blocksize);
|
||||
offset += blocksize;
|
||||
eeprom_size -= blocksize;
|
||||
}
|
||||
|
||||
ret = p54_parse_eeprom(dev, eeprom, offset);
|
||||
free:
|
||||
kfree(priv->eeprom);
|
||||
priv->eeprom = NULL;
|
||||
kfree(hdr);
|
||||
kfree(eeprom);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(p54_read_eeprom);
|
||||
|
||||
static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
@ -675,12 +780,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
|
||||
const u8 *dst, const u8 *src, u8 antenna,
|
||||
u32 magic3, u32 magic8, u32 magic9)
|
||||
const u8 *bssid)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct p54_control_hdr *hdr;
|
||||
struct p54_tx_control_filter *filter;
|
||||
size_t data_len;
|
||||
|
||||
hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
|
||||
priv->tx_hdr_len, GFP_ATOMIC);
|
||||
|
@ -691,25 +796,35 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
|
|||
|
||||
filter = (struct p54_tx_control_filter *) hdr->data;
|
||||
hdr->magic1 = cpu_to_le16(0x8001);
|
||||
hdr->len = cpu_to_le16(sizeof(*filter));
|
||||
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
|
||||
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
|
||||
|
||||
filter->filter_type = cpu_to_le16(filter_type);
|
||||
memcpy(filter->dst, dst, ETH_ALEN);
|
||||
if (!src)
|
||||
memset(filter->src, ~0, ETH_ALEN);
|
||||
priv->filter_type = filter->filter_type = cpu_to_le16(filter_type);
|
||||
memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN);
|
||||
if (!bssid)
|
||||
memset(filter->bssid, ~0, ETH_ALEN);
|
||||
else
|
||||
memcpy(filter->src, src, ETH_ALEN);
|
||||
filter->antenna = antenna;
|
||||
filter->magic3 = cpu_to_le32(magic3);
|
||||
filter->rx_addr = cpu_to_le32(priv->rx_end);
|
||||
filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */
|
||||
filter->rxhw = priv->rxhw;
|
||||
filter->magic8 = cpu_to_le16(magic8);
|
||||
filter->magic9 = cpu_to_le16(magic9);
|
||||
memcpy(filter->bssid, bssid, ETH_ALEN);
|
||||
|
||||
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
|
||||
filter->rx_antenna = priv->rx_antenna;
|
||||
|
||||
if (priv->fw_var < 0x500) {
|
||||
data_len = P54_TX_CONTROL_FILTER_V1_LEN;
|
||||
filter->v1.basic_rate_mask = cpu_to_le32(0x15F);
|
||||
filter->v1.rx_addr = cpu_to_le32(priv->rx_end);
|
||||
filter->v1.max_rx = cpu_to_le16(priv->rx_mtu);
|
||||
filter->v1.rxhw = cpu_to_le16(priv->rxhw);
|
||||
filter->v1.wakeup_timer = cpu_to_le16(500);
|
||||
} else {
|
||||
data_len = P54_TX_CONTROL_FILTER_V2_LEN;
|
||||
filter->v2.rx_addr = cpu_to_le32(priv->rx_end);
|
||||
filter->v2.max_rx = cpu_to_le16(priv->rx_mtu);
|
||||
filter->v2.rxhw = cpu_to_le16(priv->rxhw);
|
||||
filter->v2.timer = cpu_to_le16(1000);
|
||||
}
|
||||
|
||||
hdr->len = cpu_to_le16(data_len);
|
||||
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
|
||||
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -719,6 +834,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
|
|||
struct p54_control_hdr *hdr;
|
||||
struct p54_tx_control_channel *chan;
|
||||
unsigned int i;
|
||||
size_t data_len;
|
||||
void *entry;
|
||||
|
||||
hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) +
|
||||
|
@ -731,9 +847,8 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
|
|||
chan = (struct p54_tx_control_channel *) hdr->data;
|
||||
|
||||
hdr->magic1 = cpu_to_le16(0x8001);
|
||||
hdr->len = cpu_to_le16(sizeof(*chan));
|
||||
|
||||
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
|
||||
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan));
|
||||
|
||||
chan->flags = cpu_to_le16(0x1);
|
||||
chan->dwell = cpu_to_le16(0x0);
|
||||
|
@ -785,10 +900,20 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
|
|||
break;
|
||||
}
|
||||
|
||||
chan->rssical_mul = cpu_to_le16(130);
|
||||
chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */
|
||||
if (priv->fw_var < 0x500) {
|
||||
data_len = P54_TX_CONTROL_CHANNEL_V1_LEN;
|
||||
chan->v1.rssical_mul = cpu_to_le16(130);
|
||||
chan->v1.rssical_add = cpu_to_le16(0xfe70);
|
||||
} else {
|
||||
data_len = P54_TX_CONTROL_CHANNEL_V2_LEN;
|
||||
chan->v2.rssical_mul = cpu_to_le16(130);
|
||||
chan->v2.rssical_add = cpu_to_le16(0xfe70);
|
||||
chan->v2.basic_rate_mask = cpu_to_le32(0x15f);
|
||||
}
|
||||
|
||||
priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1);
|
||||
hdr->len = cpu_to_le16(data_len);
|
||||
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len);
|
||||
priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -933,12 +1058,11 @@ static int p54_add_interface(struct ieee80211_hw *dev,
|
|||
|
||||
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
|
||||
|
||||
p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
|
||||
p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
|
||||
p54_set_filter(dev, 0, NULL);
|
||||
|
||||
switch (conf->type) {
|
||||
case IEEE80211_IF_TYPE_STA:
|
||||
p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
|
||||
p54_set_filter(dev, 1, NULL);
|
||||
break;
|
||||
default:
|
||||
BUG(); /* impossible */
|
||||
|
@ -956,7 +1080,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
|
|||
struct p54_common *priv = dev->priv;
|
||||
priv->mode = IEEE80211_IF_TYPE_MNTR;
|
||||
memset(priv->mac_addr, 0, ETH_ALEN);
|
||||
p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
|
||||
p54_set_filter(dev, 0, NULL);
|
||||
}
|
||||
|
||||
static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
|
||||
|
@ -965,6 +1089,8 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
|
|||
struct p54_common *priv = dev->priv;
|
||||
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
priv->rx_antenna = (conf->antenna_sel_rx == 0) ?
|
||||
2 : conf->antenna_sel_tx - 1;
|
||||
ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
|
||||
p54_set_vdcf(dev);
|
||||
mutex_unlock(&priv->conf_mutex);
|
||||
|
@ -978,8 +1104,7 @@ static int p54_config_interface(struct ieee80211_hw *dev,
|
|||
struct p54_common *priv = dev->priv;
|
||||
|
||||
mutex_lock(&priv->conf_mutex);
|
||||
p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
|
||||
p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
|
||||
p54_set_filter(dev, 0, conf->bssid);
|
||||
p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
|
||||
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
|
||||
mutex_unlock(&priv->conf_mutex);
|
||||
|
@ -997,11 +1122,9 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
|
|||
|
||||
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
|
||||
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
|
||||
p54_set_filter(dev, 0, priv->mac_addr,
|
||||
NULL, 2, 0, 0, 0);
|
||||
p54_set_filter(dev, 0, NULL);
|
||||
else
|
||||
p54_set_filter(dev, 0, priv->mac_addr,
|
||||
priv->bssid, 2, 0, 0, 0);
|
||||
p54_set_filter(dev, 0, priv->bssid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1068,10 +1191,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|||
priv = dev->priv;
|
||||
priv->mode = IEEE80211_IF_TYPE_INVALID;
|
||||
skb_queue_head_init(&priv->tx_queue);
|
||||
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
|
||||
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
|
||||
IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_SIGNAL_UNSPEC;
|
||||
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
dev->channel_change_time = 1000; /* TODO: find actual value */
|
||||
dev->max_signal = 127;
|
||||
|
||||
|
@ -1081,11 +1206,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
|
|||
priv->tx_stats[3].limit = 1;
|
||||
priv->tx_stats[4].limit = 5;
|
||||
dev->queues = 1;
|
||||
|
||||
dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
|
||||
sizeof(struct p54_tx_control_allocdata);
|
||||
|
||||
mutex_init(&priv->conf_mutex);
|
||||
init_completion(&priv->eeprom_comp);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,17 @@ struct bootrec_exp_if {
|
|||
__le16 top_compat;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bootrec_desc {
|
||||
__le16 modes;
|
||||
__le16 flags;
|
||||
__le32 rx_start;
|
||||
__le32 rx_end;
|
||||
u8 headroom;
|
||||
u8 tailroom;
|
||||
u8 unimportant[6];
|
||||
u8 rates[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define BR_CODE_MIN 0x80000000
|
||||
#define BR_CODE_COMPONENT_ID 0x80000001
|
||||
#define BR_CODE_COMPONENT_VERSION 0x80000002
|
||||
|
@ -39,11 +50,6 @@ struct bootrec_exp_if {
|
|||
#define BR_CODE_END_OF_BRA 0xFF0000FF
|
||||
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
|
||||
|
||||
#define FW_FMAC 0x464d4143
|
||||
#define FW_LM86 0x4c4d3836
|
||||
#define FW_LM87 0x4c4d3837
|
||||
#define FW_LM20 0x4c4d3230
|
||||
|
||||
/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
|
||||
|
||||
struct pda_entry {
|
||||
|
@ -180,7 +186,7 @@ struct p54_rx_hdr {
|
|||
u8 quality;
|
||||
u16 unknown2;
|
||||
__le64 timestamp;
|
||||
u8 data[0];
|
||||
u8 align[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct p54_frame_sent_hdr {
|
||||
|
@ -208,19 +214,34 @@ struct p54_tx_control_allocdata {
|
|||
|
||||
struct p54_tx_control_filter {
|
||||
__le16 filter_type;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 src[ETH_ALEN];
|
||||
u8 antenna;
|
||||
u8 debug;
|
||||
__le32 magic3;
|
||||
u8 rates[8]; // FIXME: what's this for?
|
||||
__le32 rx_addr;
|
||||
__le16 max_rx;
|
||||
__le16 rxhw;
|
||||
__le16 magic8;
|
||||
__le16 magic9;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 bssid[ETH_ALEN];
|
||||
u8 rx_antenna;
|
||||
u8 rx_align;
|
||||
union {
|
||||
struct {
|
||||
__le32 basic_rate_mask;
|
||||
u8 rts_rates[8];
|
||||
__le32 rx_addr;
|
||||
__le16 max_rx;
|
||||
__le16 rxhw;
|
||||
__le16 wakeup_timer;
|
||||
__le16 unalloc0;
|
||||
} v1 __attribute__ ((packed));
|
||||
struct {
|
||||
__le32 rx_addr;
|
||||
__le16 max_rx;
|
||||
__le16 rxhw;
|
||||
__le16 timer;
|
||||
__le16 unalloc0;
|
||||
__le32 unalloc1;
|
||||
} v2 __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter))
|
||||
#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8)
|
||||
|
||||
struct p54_tx_control_channel {
|
||||
__le16 flags;
|
||||
__le16 dwell;
|
||||
|
@ -232,15 +253,29 @@ struct p54_tx_control_channel {
|
|||
u8 val_qpsk;
|
||||
u8 val_16qam;
|
||||
u8 val_64qam;
|
||||
struct pda_pa_curve_data_sample_rev1 curve_data[8];
|
||||
struct p54_pa_curve_data_sample curve_data[8];
|
||||
u8 dup_bpsk;
|
||||
u8 dup_qpsk;
|
||||
u8 dup_16qam;
|
||||
u8 dup_64qam;
|
||||
__le16 rssical_mul;
|
||||
__le16 rssical_add;
|
||||
union {
|
||||
struct {
|
||||
__le16 rssical_mul;
|
||||
__le16 rssical_add;
|
||||
} v1 __attribute__ ((packed));
|
||||
|
||||
struct {
|
||||
__le32 basic_rate_mask;
|
||||
u8 rts_rates[8];
|
||||
__le16 rssical_mul;
|
||||
__le16 rssical_add;
|
||||
} v2 __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12)
|
||||
#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel))
|
||||
|
||||
struct p54_tx_control_led {
|
||||
__le16 mode;
|
||||
__le16 led_temporary;
|
||||
|
|
|
@ -72,8 +72,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
|
|||
P54P_WRITE(ctrl_stat, reg);
|
||||
wmb();
|
||||
|
||||
mdelay(50);
|
||||
|
||||
err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s (p54pci): cannot find firmware "
|
||||
|
@ -81,7 +79,11 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
p54_parse_firmware(dev, fw_entry);
|
||||
err = p54_parse_firmware(dev, fw_entry);
|
||||
if (err) {
|
||||
release_firmware(fw_entry);
|
||||
return err;
|
||||
}
|
||||
|
||||
data = (__le32 *) fw_entry->data;
|
||||
remains = fw_entry->size;
|
||||
|
@ -122,120 +124,10 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
|
|||
wmb();
|
||||
udelay(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct p54p_priv *priv = (struct p54p_priv *) dev_id;
|
||||
__le32 reg;
|
||||
|
||||
reg = P54P_READ(int_ident);
|
||||
P54P_WRITE(int_ack, reg);
|
||||
|
||||
if (reg & P54P_READ(int_enable))
|
||||
complete(&priv->boot_comp);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int p54p_read_eeprom(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct p54p_priv *priv = dev->priv;
|
||||
struct p54p_ring_control *ring_control = priv->ring_control;
|
||||
int err;
|
||||
struct p54_control_hdr *hdr;
|
||||
void *eeprom;
|
||||
dma_addr_t rx_mapping, tx_mapping;
|
||||
u16 alen;
|
||||
|
||||
init_completion(&priv->boot_comp);
|
||||
err = request_irq(priv->pdev->irq, &p54p_simple_interrupt,
|
||||
IRQF_SHARED, "p54pci", priv);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s (p54pci): failed to register IRQ handler\n",
|
||||
pci_name(priv->pdev));
|
||||
return err;
|
||||
}
|
||||
|
||||
eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL);
|
||||
if (!eeprom) {
|
||||
printk(KERN_ERR "%s (p54pci): no memory for eeprom!\n",
|
||||
pci_name(priv->pdev));
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(ring_control, 0, sizeof(*ring_control));
|
||||
P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
|
||||
P54P_READ(ring_control_base);
|
||||
udelay(10);
|
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
|
||||
P54P_READ(int_enable);
|
||||
udelay(10);
|
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
|
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
|
||||
printk(KERN_ERR "%s (p54pci): Cannot boot firmware!\n",
|
||||
pci_name(priv->pdev));
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
|
||||
P54P_READ(int_enable);
|
||||
|
||||
hdr = eeprom + 0x2010;
|
||||
p54_fill_eeprom_readback(hdr);
|
||||
hdr->req_id = cpu_to_le32(priv->common.rx_start);
|
||||
|
||||
rx_mapping = pci_map_single(priv->pdev, eeprom,
|
||||
0x2010, PCI_DMA_FROMDEVICE);
|
||||
tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
|
||||
EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
|
||||
|
||||
ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
|
||||
ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
|
||||
ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
|
||||
ring_control->tx_data[0].device_addr = hdr->req_id;
|
||||
ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
|
||||
|
||||
ring_control->host_idx[2] = cpu_to_le32(1);
|
||||
ring_control->host_idx[1] = cpu_to_le32(1);
|
||||
|
||||
wmb();
|
||||
/* wait for the firmware to boot properly */
|
||||
mdelay(100);
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
|
||||
|
||||
wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
|
||||
wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
|
||||
|
||||
pci_unmap_single(priv->pdev, tx_mapping,
|
||||
EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
|
||||
pci_unmap_single(priv->pdev, rx_mapping,
|
||||
0x2010, PCI_DMA_FROMDEVICE);
|
||||
|
||||
alen = le16_to_cpu(ring_control->rx_mgmt[0].len);
|
||||
if (le32_to_cpu(ring_control->device_idx[2]) != 1 ||
|
||||
alen < 0x10) {
|
||||
printk(KERN_ERR "%s (p54pci): Cannot read eeprom!\n",
|
||||
pci_name(priv->pdev));
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10);
|
||||
|
||||
out:
|
||||
kfree(eeprom);
|
||||
P54P_WRITE(int_enable, cpu_to_le32(0));
|
||||
P54P_READ(int_enable);
|
||||
udelay(10);
|
||||
free_irq(priv->pdev->irq, priv);
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
|
||||
|
@ -258,17 +150,17 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
|
|||
if (!desc->host_addr) {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t mapping;
|
||||
skb = dev_alloc_skb(MAX_RX_SIZE);
|
||||
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
mapping = pci_map_single(priv->pdev,
|
||||
skb_tail_pointer(skb),
|
||||
MAX_RX_SIZE,
|
||||
priv->common.rx_mtu + 32,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
desc->host_addr = cpu_to_le32(mapping);
|
||||
desc->device_addr = 0; // FIXME: necessary?
|
||||
desc->len = cpu_to_le16(MAX_RX_SIZE);
|
||||
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
|
||||
desc->flags = 0;
|
||||
rx_buf[i] = skb;
|
||||
}
|
||||
|
@ -301,20 +193,23 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
|
|||
len = le16_to_cpu(desc->len);
|
||||
skb = rx_buf[i];
|
||||
|
||||
if (!skb)
|
||||
if (!skb) {
|
||||
i++;
|
||||
i %= ring_limit;
|
||||
continue;
|
||||
|
||||
}
|
||||
skb_put(skb, len);
|
||||
|
||||
if (p54_rx(dev, skb)) {
|
||||
pci_unmap_single(priv->pdev,
|
||||
le32_to_cpu(desc->host_addr),
|
||||
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
|
||||
priv->common.rx_mtu + 32,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
rx_buf[i] = NULL;
|
||||
desc->host_addr = 0;
|
||||
} else {
|
||||
skb_trim(skb, 0);
|
||||
desc->len = cpu_to_le16(MAX_RX_SIZE);
|
||||
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
@ -466,6 +361,11 @@ static int p54p_open(struct ieee80211_hw *dev)
|
|||
}
|
||||
|
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control));
|
||||
err = p54p_upload_firmware(dev);
|
||||
if (err) {
|
||||
free_irq(priv->pdev->irq, dev);
|
||||
return err;
|
||||
}
|
||||
priv->rx_idx_data = priv->tx_idx_data = 0;
|
||||
priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
|
||||
|
||||
|
@ -475,8 +375,6 @@ static int p54p_open(struct ieee80211_hw *dev)
|
|||
p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
|
||||
ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
|
||||
|
||||
p54p_upload_firmware(dev);
|
||||
|
||||
P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
|
||||
P54P_READ(ring_control_base);
|
||||
wmb();
|
||||
|
@ -532,7 +430,8 @@ static void p54p_stop(struct ieee80211_hw *dev)
|
|||
if (desc->host_addr)
|
||||
pci_unmap_single(priv->pdev,
|
||||
le32_to_cpu(desc->host_addr),
|
||||
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
|
||||
priv->common.rx_mtu + 32,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
kfree_skb(priv->rx_buf_data[i]);
|
||||
priv->rx_buf_data[i] = NULL;
|
||||
}
|
||||
|
@ -542,7 +441,8 @@ static void p54p_stop(struct ieee80211_hw *dev)
|
|||
if (desc->host_addr)
|
||||
pci_unmap_single(priv->pdev,
|
||||
le32_to_cpu(desc->host_addr),
|
||||
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
|
||||
priv->common.rx_mtu + 32,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
kfree_skb(priv->rx_buf_mgmt[i]);
|
||||
priv->rx_buf_mgmt[i] = NULL;
|
||||
}
|
||||
|
@ -649,16 +549,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
|
|||
err = -ENOMEM;
|
||||
goto err_iounmap;
|
||||
}
|
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control));
|
||||
|
||||
err = p54p_upload_firmware(dev);
|
||||
if (err)
|
||||
goto err_free_desc;
|
||||
|
||||
err = p54p_read_eeprom(dev);
|
||||
if (err)
|
||||
goto err_free_desc;
|
||||
|
||||
priv->common.open = p54p_open;
|
||||
priv->common.stop = p54p_stop;
|
||||
priv->common.tx = p54p_tx;
|
||||
|
@ -666,6 +556,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
|
|||
spin_lock_init(&priv->lock);
|
||||
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
|
||||
|
||||
p54p_open(dev);
|
||||
err = p54_read_eeprom(dev);
|
||||
p54p_stop(dev);
|
||||
if (err)
|
||||
goto err_free_desc;
|
||||
|
||||
err = ieee80211_register_hw(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n",
|
||||
|
@ -673,11 +569,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
|
|||
goto err_free_common;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
|
||||
wiphy_name(dev->wiphy),
|
||||
print_mac(mac, dev->wiphy->perm_addr),
|
||||
priv->common.version);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_common:
|
||||
|
|
|
@ -91,11 +91,16 @@ static void p54u_rx_cb(struct urb *urb)
|
|||
|
||||
skb_unlink(skb, &priv->rx_queue);
|
||||
skb_put(skb, urb->actual_length);
|
||||
if (!priv->hw_type)
|
||||
skb_pull(skb, sizeof(struct net2280_tx_hdr));
|
||||
|
||||
if (priv->hw_type == P54U_NET2280)
|
||||
skb_pull(skb, priv->common.tx_hdr_len);
|
||||
if (priv->common.fw_interface == FW_LM87) {
|
||||
skb_pull(skb, 4);
|
||||
skb_put(skb, 4);
|
||||
}
|
||||
|
||||
if (p54_rx(dev, skb)) {
|
||||
skb = dev_alloc_skb(MAX_RX_SIZE);
|
||||
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
|
||||
if (unlikely(!skb)) {
|
||||
usb_free_urb(urb);
|
||||
/* TODO check rx queue length and refill *somewhere* */
|
||||
|
@ -109,9 +114,12 @@ static void p54u_rx_cb(struct urb *urb)
|
|||
urb->context = skb;
|
||||
skb_queue_tail(&priv->rx_queue, skb);
|
||||
} else {
|
||||
if (!priv->hw_type)
|
||||
skb_push(skb, sizeof(struct net2280_tx_hdr));
|
||||
|
||||
if (priv->hw_type == P54U_NET2280)
|
||||
skb_push(skb, priv->common.tx_hdr_len);
|
||||
if (priv->common.fw_interface == FW_LM87) {
|
||||
skb_push(skb, 4);
|
||||
skb_put(skb, 4);
|
||||
}
|
||||
skb_reset_tail_pointer(skb);
|
||||
skb_trim(skb, 0);
|
||||
if (urb->transfer_buffer != skb_tail_pointer(skb)) {
|
||||
|
@ -145,7 +153,7 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
|
|||
struct p54u_rx_info *info;
|
||||
|
||||
while (skb_queue_len(&priv->rx_queue) < 32) {
|
||||
skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
|
||||
skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
|
||||
if (!skb)
|
||||
break;
|
||||
entry = usb_alloc_urb(0, GFP_KERNEL);
|
||||
|
@ -153,7 +161,10 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
|
|||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
|
||||
usb_fill_bulk_urb(entry, priv->udev,
|
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
|
||||
skb_tail_pointer(skb),
|
||||
priv->common.rx_mtu + 32, p54u_rx_cb, skb);
|
||||
info = (struct p54u_rx_info *) skb->cb;
|
||||
info->urb = entry;
|
||||
info->dev = dev;
|
||||
|
@ -207,6 +218,42 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
|
|||
usb_submit_urb(data_urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
__le32 p54u_lm87_chksum(const u32 *data, size_t length)
|
||||
{
|
||||
__le32 chk = 0;
|
||||
|
||||
length >>= 2;
|
||||
while (length--) {
|
||||
chk ^= cpu_to_le32(*data++);
|
||||
chk = (chk >> 5) ^ (chk << 3);
|
||||
}
|
||||
|
||||
return chk;
|
||||
}
|
||||
|
||||
static void p54u_tx_lm87(struct ieee80211_hw *dev,
|
||||
struct p54_control_hdr *data,
|
||||
size_t len, int free_on_tx)
|
||||
{
|
||||
struct p54u_priv *priv = dev->priv;
|
||||
struct urb *data_urb;
|
||||
struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr);
|
||||
|
||||
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!data_urb)
|
||||
return;
|
||||
|
||||
hdr->chksum = p54u_lm87_chksum((u32 *)data, len);
|
||||
hdr->device_addr = data->req_id;
|
||||
|
||||
usb_fill_bulk_urb(data_urb, priv->udev,
|
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr,
|
||||
len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb,
|
||||
dev);
|
||||
|
||||
usb_submit_urb(data_urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
|
||||
size_t len, int free_on_tx)
|
||||
{
|
||||
|
@ -312,73 +359,6 @@ static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
|
|||
data, len, &alen, 2000);
|
||||
}
|
||||
|
||||
static int p54u_read_eeprom(struct ieee80211_hw *dev)
|
||||
{
|
||||
struct p54u_priv *priv = dev->priv;
|
||||
void *buf;
|
||||
struct p54_control_hdr *hdr;
|
||||
int err, alen;
|
||||
size_t offset = priv->hw_type ? 0x10 : 0x20;
|
||||
|
||||
buf = kmalloc(0x2020, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
printk(KERN_ERR "p54usb: cannot allocate memory for "
|
||||
"eeprom readback!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (priv->hw_type) {
|
||||
*((u32 *) buf) = priv->common.rx_start;
|
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
|
||||
if (err) {
|
||||
printk(KERN_ERR "p54usb: addr send failed\n");
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
struct net2280_reg_write *reg = buf;
|
||||
reg->port = cpu_to_le16(NET2280_DEV_U32);
|
||||
reg->addr = cpu_to_le32(P54U_DEV_BASE);
|
||||
reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
|
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
|
||||
if (err) {
|
||||
printk(KERN_ERR "p54usb: dev_int send failed\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
hdr = buf + priv->common.tx_hdr_len;
|
||||
p54_fill_eeprom_readback(hdr);
|
||||
hdr->req_id = cpu_to_le32(priv->common.rx_start);
|
||||
if (priv->common.tx_hdr_len) {
|
||||
struct net2280_tx_hdr *tx_hdr = buf;
|
||||
tx_hdr->device_addr = hdr->req_id;
|
||||
tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
|
||||
}
|
||||
|
||||
/* we can just pretend to send 0x2000 bytes of nothing in the headers */
|
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
|
||||
EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
|
||||
if (err) {
|
||||
printk(KERN_ERR "p54usb: eeprom req send failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = usb_bulk_msg(priv->udev,
|
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
|
||||
buf, 0x2020, &alen, 1000);
|
||||
if (!err && alen > offset) {
|
||||
p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
|
||||
} else {
|
||||
printk(KERN_ERR "p54usb: eeprom read failed!\n");
|
||||
err = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
kfree(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
|
||||
{
|
||||
static char start_string[] = "~~~~<\r";
|
||||
|
@ -412,7 +392,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
|
|||
goto err_req_fw_failed;
|
||||
}
|
||||
|
||||
p54_parse_firmware(dev, fw_entry);
|
||||
err = p54_parse_firmware(dev, fw_entry);
|
||||
if (err)
|
||||
goto err_upload_failed;
|
||||
|
||||
left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
|
||||
strcpy(buf, start_string);
|
||||
|
@ -549,7 +531,12 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
p54_parse_firmware(dev, fw_entry);
|
||||
err = p54_parse_firmware(dev, fw_entry);
|
||||
if (err) {
|
||||
kfree(buf);
|
||||
release_firmware(fw_entry);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define P54U_WRITE(type, addr, data) \
|
||||
do {\
|
||||
|
@ -833,49 +820,40 @@ static int __devinit p54u_probe(struct usb_interface *intf,
|
|||
}
|
||||
}
|
||||
priv->common.open = p54u_open;
|
||||
|
||||
priv->common.stop = p54u_stop;
|
||||
if (recognized_pipes < P54U_PIPE_NUMBER) {
|
||||
priv->hw_type = P54U_3887;
|
||||
priv->common.tx = p54u_tx_3887;
|
||||
err = p54u_upload_firmware_3887(dev);
|
||||
if (priv->common.fw_interface == FW_LM87) {
|
||||
dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
|
||||
priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
|
||||
priv->common.tx = p54u_tx_lm87;
|
||||
} else
|
||||
priv->common.tx = p54u_tx_3887;
|
||||
} else {
|
||||
priv->hw_type = P54U_NET2280;
|
||||
dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
|
||||
priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
|
||||
priv->common.tx = p54u_tx_net2280;
|
||||
}
|
||||
priv->common.stop = p54u_stop;
|
||||
|
||||
if (priv->hw_type)
|
||||
err = p54u_upload_firmware_3887(dev);
|
||||
else
|
||||
err = p54u_upload_firmware_net2280(dev);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
err = p54u_read_eeprom(dev);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
printk(KERN_WARNING "p54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
|
||||
random_ether_addr(perm_addr);
|
||||
SET_IEEE80211_PERM_ADDR(dev, perm_addr);
|
||||
}
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
skb_queue_head_init(&priv->rx_queue);
|
||||
|
||||
p54u_open(dev);
|
||||
err = p54_read_eeprom(dev);
|
||||
p54u_stop(dev);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
err = ieee80211_register_hw(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "p54usb: Cannot register netdevice\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
|
||||
wiphy_name(dev->wiphy),
|
||||
print_mac(mac, dev->wiphy->perm_addr),
|
||||
priv->common.version);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_dev:
|
||||
|
|
|
@ -72,6 +72,11 @@ struct net2280_tx_hdr {
|
|||
u8 padding[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct lm87_tx_hdr {
|
||||
__le32 device_addr;
|
||||
__le32 chksum;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Some flags for the isl hardware registers controlling DMA inside the
|
||||
* chip */
|
||||
#define ISL38XX_DMA_STATUS_DONE 0x00000001
|
||||
|
|
|
@ -1052,6 +1052,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
*/
|
||||
rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
|
||||
|
||||
rt2x00dev->hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_AP) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
/*
|
||||
* Let the driver probe the device to detect the capabilities.
|
||||
*/
|
||||
|
|
|
@ -1184,6 +1184,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
|
|||
dev->max_signal = 65;
|
||||
}
|
||||
|
||||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
|
||||
printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
|
||||
" info!\n");
|
||||
|
|
|
@ -937,6 +937,11 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
|
|||
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||
IEEE80211_HW_SIGNAL_DB;
|
||||
|
||||
hw->wiphy->interface_modes =
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->max_signal = 100;
|
||||
hw->queues = 1;
|
||||
hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
|
||||
|
|
|
@ -210,6 +210,10 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
|
||||
* association request when used with NL80211_CMD_NEW_STATION)
|
||||
*
|
||||
* @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
|
||||
* supported interface types, each a flag attribute with the number
|
||||
* of the interface mode.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -259,6 +263,8 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_HT_CAPABILITY,
|
||||
|
||||
NL80211_ATTR_SUPPORTED_IFTYPES,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
|
|
@ -185,6 +185,9 @@ struct wiphy {
|
|||
/* permanent MAC address */
|
||||
u8 perm_addr[ETH_ALEN];
|
||||
|
||||
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
|
||||
u16 interface_modes;
|
||||
|
||||
/* If multiple wiphys are registered and you're handed e.g.
|
||||
* a regular netdev with assigned ieee80211_ptr, you won't
|
||||
* know whether it points to a wiphy your driver has registered
|
||||
|
|
|
@ -1675,6 +1675,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
}
|
||||
}
|
||||
|
||||
/* if low-level driver supports AP, we also support VLAN */
|
||||
if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
|
||||
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
|
||||
|
||||
/* mac80211 always supports monitor */
|
||||
local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
|
||||
|
||||
result = wiphy_register(local->hw.wiphy);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
|
|
@ -2557,6 +2557,33 @@ u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
|||
return supp_rates;
|
||||
}
|
||||
|
||||
static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_rate *bitrates;
|
||||
u64 mandatory_rates;
|
||||
enum ieee80211_rate_flags mandatory_flag;
|
||||
int i;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (!sband) {
|
||||
WARN_ON(1);
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
}
|
||||
|
||||
if (band == IEEE80211_BAND_2GHZ)
|
||||
mandatory_flag = IEEE80211_RATE_MANDATORY_B;
|
||||
else
|
||||
mandatory_flag = IEEE80211_RATE_MANDATORY_A;
|
||||
|
||||
bitrates = sband->bitrates;
|
||||
mandatory_rates = 0;
|
||||
for (i = 0; i < sband->n_bitrates; i++)
|
||||
if (bitrates[i].flags & mandatory_flag)
|
||||
mandatory_rates |= BIT(i);
|
||||
return mandatory_rates;
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
|
@ -2568,9 +2595,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
int freq, clen;
|
||||
struct ieee80211_sta_bss *bss;
|
||||
struct sta_info *sta;
|
||||
u64 beacon_timestamp, rx_timestamp;
|
||||
struct ieee80211_channel *channel;
|
||||
u64 beacon_timestamp, rx_timestamp;
|
||||
u64 supp_rates = 0;
|
||||
bool beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
enum ieee80211_band band = rx_status->band;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
DECLARE_MAC_BUF(mac2);
|
||||
|
||||
|
@ -2578,30 +2607,41 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
|
||||
elems->mesh_config && mesh_matches_local(elems, sdata)) {
|
||||
u64 rates = ieee80211_sta_get_rates(local, elems,
|
||||
rx_status->band);
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
||||
|
||||
mesh_neighbour_update(mgmt->sa, rates, sdata,
|
||||
mesh_neighbour_update(mgmt->sa, supp_rates, sdata,
|
||||
mesh_peer_accepts_plinks(elems));
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
|
||||
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
|
||||
(sta = sta_info_get(local, mgmt->sa))) {
|
||||
u64 prev_rates;
|
||||
u64 supp_rates = ieee80211_sta_get_rates(local, elems,
|
||||
rx_status->band);
|
||||
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
|
||||
|
||||
prev_rates = sta->supp_rates[rx_status->band];
|
||||
sta->supp_rates[rx_status->band] &= supp_rates;
|
||||
if (sta->supp_rates[rx_status->band] == 0) {
|
||||
/* No matching rates - this should not really happen.
|
||||
* Make sure that at least one rate is marked
|
||||
* supported to avoid issues with TX rate ctrl. */
|
||||
sta->supp_rates[rx_status->band] =
|
||||
sdata->u.sta.supp_rates_bits[rx_status->band];
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
||||
|
||||
sta = sta_info_get(local, mgmt->sa);
|
||||
if (sta) {
|
||||
u64 prev_rates;
|
||||
|
||||
prev_rates = sta->supp_rates[band];
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->supp_rates[band] = supp_rates |
|
||||
ieee80211_sta_get_mandatory_rates(local, band);
|
||||
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
if (sta->supp_rates[band] != prev_rates)
|
||||
printk(KERN_DEBUG "%s: updated supp_rates set "
|
||||
"for %s based on beacon info (0x%llx | "
|
||||
"0x%llx -> 0x%llx)\n",
|
||||
sdata->dev->name, print_mac(mac, sta->addr),
|
||||
(unsigned long long) prev_rates,
|
||||
(unsigned long long) supp_rates,
|
||||
(unsigned long long) sta->supp_rates[band]);
|
||||
#endif
|
||||
} else {
|
||||
ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid,
|
||||
mgmt->sa, supp_rates);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2683,7 +2723,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
bss->supp_rates_len += clen;
|
||||
}
|
||||
|
||||
bss->band = rx_status->band;
|
||||
bss->band = band;
|
||||
|
||||
bss->timestamp = beacon_timestamp;
|
||||
bss->last_update = jiffies;
|
||||
|
@ -2738,7 +2778,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
* e.g: at 1 MBit that means mactime is 192 usec earlier
|
||||
* (=24 bytes * 8 usecs/byte) than the beacon timestamp.
|
||||
*/
|
||||
int rate = local->hw.wiphy->bands[rx_status->band]->
|
||||
int rate = local->hw.wiphy->bands[band]->
|
||||
bitrates[rx_status->rate_idx].bitrate;
|
||||
rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
|
||||
} else if (local && local->ops && local->ops->get_tsf)
|
||||
|
@ -2766,7 +2806,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
|
||||
ieee80211_ibss_add_sta(sdata, NULL,
|
||||
mgmt->bssid, mgmt->sa,
|
||||
BIT(rx_status->rate_idx));
|
||||
supp_rates);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3032,7 +3072,6 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *
|
|||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
||||
static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -4316,10 +4355,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
set_sta_flags(sta, WLAN_STA_AUTHORIZED);
|
||||
|
||||
if (supp_rates)
|
||||
sta->supp_rates[band] = supp_rates;
|
||||
else
|
||||
sta->supp_rates[band] = sdata->u.sta.supp_rates_bits[band];
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->supp_rates[band] = supp_rates |
|
||||
ieee80211_sta_get_mandatory_rates(local, band);
|
||||
|
||||
rate_control_rate_init(sta, local);
|
||||
|
||||
|
|
|
@ -1743,10 +1743,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
|
|||
if (!bssid)
|
||||
return 0;
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
if (!rx->sta)
|
||||
rx->sta = ieee80211_ibss_add_sta(sdata,
|
||||
rx->skb, bssid, hdr->addr2,
|
||||
BIT(rx->status->rate_idx));
|
||||
return 1;
|
||||
}
|
||||
else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
|
||||
|
|
|
@ -204,6 +204,7 @@ struct sta_ampdu_mlme {
|
|||
* @tx_fragments: number of transmitted MPDUs
|
||||
* @txrate_idx: TBD
|
||||
* @last_txrate_idx: TBD
|
||||
* @tid_seq: TBD
|
||||
* @wme_tx_queue: TBD
|
||||
* @ampdu_mlme: TBD
|
||||
* @timer_to_tid: identity mapping to ID timers
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This is the linux wireless configuration interface.
|
||||
*
|
||||
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
|
||||
#include <linux/if.h>
|
||||
|
@ -259,6 +259,13 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
struct ieee80211_supported_band *sband;
|
||||
bool have_band = false;
|
||||
int i;
|
||||
u16 ifmodes = wiphy->interface_modes;
|
||||
|
||||
/* sanity check ifmodes */
|
||||
WARN_ON(!ifmodes);
|
||||
ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
|
||||
if (WARN_ON(ifmodes != wiphy->interface_modes))
|
||||
wiphy->interface_modes = ifmodes;
|
||||
|
||||
/* sanity check supported bands/channels */
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
|
|
|
@ -113,10 +113,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
struct nlattr *nl_bands, *nl_band;
|
||||
struct nlattr *nl_freqs, *nl_freq;
|
||||
struct nlattr *nl_rates, *nl_rate;
|
||||
struct nlattr *nl_modes;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_rate *rate;
|
||||
int i;
|
||||
u16 ifmodes = dev->wiphy.interface_modes;
|
||||
|
||||
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
|
||||
if (!hdr)
|
||||
|
@ -125,6 +127,20 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
|
||||
NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
|
||||
|
||||
nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
|
||||
if (!nl_modes)
|
||||
goto nla_put_failure;
|
||||
|
||||
i = 0;
|
||||
while (ifmodes) {
|
||||
if (ifmodes & 1)
|
||||
NLA_PUT_FLAG(msg, i);
|
||||
ifmodes >>= 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_modes);
|
||||
|
||||
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
|
||||
if (!nl_bands)
|
||||
goto nla_put_failure;
|
||||
|
@ -415,7 +431,8 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
ifindex = dev->ifindex;
|
||||
dev_put(dev);
|
||||
|
||||
if (!drv->ops->change_virtual_intf) {
|
||||
if (!drv->ops->change_virtual_intf ||
|
||||
!(drv->wiphy.interface_modes & (1 << type))) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -462,7 +479,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
if (IS_ERR(drv))
|
||||
return PTR_ERR(drv);
|
||||
|
||||
if (!drv->ops->add_virtual_intf) {
|
||||
if (!drv->ops->add_virtual_intf ||
|
||||
!(drv->wiphy.interface_modes & (1 << type))) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto unlock;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue