Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-next-2.6

Conflicts:

	drivers/net/ps3_gelic_wireless.c
	drivers/net/wireless/libertas/main.c
This commit is contained in:
David S. Miller 2008-06-10 01:54:31 -07:00
commit 788c0a5316
135 changed files with 7601 additions and 5438 deletions

View File

@ -2284,6 +2284,19 @@ config GELIC_WIRELESS
the driver automatically distinguishes the models, you can the driver automatically distinguishes the models, you can
safely enable this option even if you have a wireless-less model. safely enable this option even if you have a wireless-less model.
config GELIC_WIRELESS_OLD_PSK_INTERFACE
bool "PS3 Wireless private PSK interface (OBSOLETE)"
depends on GELIC_WIRELESS
help
This option retains the obsolete private interface to pass
the PSK from user space programs to the driver. The PSK
stands for 'Pre Shared Key' and is used for WPA[2]-PSK
(WPA-Personal) environment.
If WPA[2]-PSK is used and you need to use old programs that
support only this old interface, say Y. Otherwise N.
If unsure, say N.
config GIANFAR config GIANFAR
tristate "Gianfar Ethernet" tristate "Gianfar Ethernet"
depends on FSL_SOC depends on FSL_SOC

View File

@ -45,7 +45,8 @@
#include "ps3_gelic_wireless.h" #include "ps3_gelic_wireless.h"
static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan); static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
u8 *essid, size_t essid_len);
static int gelic_wl_try_associate(struct net_device *netdev); static int gelic_wl_try_associate(struct net_device *netdev);
/* /*
@ -105,6 +106,7 @@ static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
[GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_START_SCAN] = { .pre_arg = 1},
[GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1}, [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1},
}; };
@ -163,7 +165,9 @@ static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
card = port_to_card(wl_port(wl)); card = port_to_card(wl_port(wl));
if (cmd_info[cmd->cmd].pre_arg) { if (cmd_info[cmd->cmd].pre_arg) {
arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer)); arg1 = (cmd->buffer) ?
ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
0;
arg2 = cmd->buf_size; arg2 = cmd->buf_size;
} else { } else {
arg1 = 0; arg1 = 0;
@ -350,7 +354,8 @@ static int gelic_wl_get_range(struct net_device *netdev,
/* encryption capability */ /* encryption capability */
range->enc_capa = IW_ENC_CAPA_WPA | range->enc_capa = IW_ENC_CAPA_WPA |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
IW_ENC_CAPA_4WAY_HANDSHAKE;
if (wpa2_capable()) if (wpa2_capable())
range->enc_capa |= IW_ENC_CAPA_WPA2; range->enc_capa |= IW_ENC_CAPA_WPA2;
range->encoding_size[0] = 5; /* 40bit WEP */ range->encoding_size[0] = 5; /* 40bit WEP */
@ -359,6 +364,9 @@ static int gelic_wl_get_range(struct net_device *netdev,
range->num_encoding_sizes = 3; range->num_encoding_sizes = 3;
range->max_encoding_tokens = GELIC_WEP_KEYS; range->max_encoding_tokens = GELIC_WEP_KEYS;
/* scan capability */
range->scan_capa = IW_SCAN_CAPA_ESSID;
pr_debug("%s: ->\n", __func__); pr_debug("%s: ->\n", __func__);
return 0; return 0;
@ -370,8 +378,18 @@ static int gelic_wl_set_scan(struct net_device *netdev,
union iwreq_data *wrqu, char *extra) union iwreq_data *wrqu, char *extra)
{ {
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
struct iw_scan_req *req;
u8 *essid = NULL;
size_t essid_len = 0;
return gelic_wl_start_scan(wl, 1); if (wrqu->data.length == sizeof(struct iw_scan_req) &&
wrqu->data.flags & IW_SCAN_THIS_ESSID) {
req = (struct iw_scan_req*)extra;
essid = req->essid;
essid_len = req->essid_len;
pr_debug("%s: ESSID scan =%s\n", __func__, essid);
}
return gelic_wl_start_scan(wl, 1, essid, essid_len);
} }
#define OUI_LEN 3 #define OUI_LEN 3
@ -1256,42 +1274,19 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
set_bit(key_index, &wl->key_enabled); set_bit(key_index, &wl->key_enabled);
/* remember wep info changed */ /* remember wep info changed */
set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { } else if (alg == IW_ENCODE_ALG_PMK) {
pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg); if (ext->key_len != WPA_PSK_LEN) {
/* check key length */ pr_err("%s: PSK length wrong %d\n", __func__,
if (IW_ENCODING_TOKEN_MAX < ext->key_len) { ext->key_len);
pr_info("%s: key is too long %d\n", __func__,
ext->key_len);
ret = -EINVAL; ret = -EINVAL;
goto done; goto done;
} }
if (alg == IW_ENCODE_ALG_CCMP) { memset(wl->psk, 0, sizeof(wl->psk));
pr_debug("%s: AES selected\n", __func__); memcpy(wl->psk, ext->key, ext->key_len);
wl->group_cipher_method = GELIC_WL_CIPHER_AES; wl->psk_len = ext->key_len;
wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES; wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2; /* remember PSK configured */
} else { set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
pr_debug("%s: TKIP selected, WPA forced\n", __func__);
wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
/* FIXME: how do we do if WPA2 + TKIP? */
wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
}
if (flags & IW_ENCODE_RESTRICTED)
BUG();
wl->auth_method = GELIC_EURUS_AUTH_OPEN;
/* We should use same key for both and unicast */
if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
pr_debug("%s: group key \n", __func__);
else
pr_debug("%s: unicast key \n", __func__);
/* OK, update the key */
wl->key_len[key_index] = ext->key_len;
memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
memcpy(wl->key[key_index], ext->key, ext->key_len);
set_bit(key_index, &wl->key_enabled);
/* remember info changed */
set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
} }
done: done:
spin_unlock_irqrestore(&wl->lock, irqflag); spin_unlock_irqrestore(&wl->lock, irqflag);
@ -1397,6 +1392,7 @@ static int gelic_wl_get_mode(struct net_device *netdev,
return 0; return 0;
} }
#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
/* SIOCIWFIRSTPRIV */ /* SIOCIWFIRSTPRIV */
static int hex2bin(u8 *str, u8 *bin, unsigned int len) static int hex2bin(u8 *str, u8 *bin, unsigned int len)
{ {
@ -1501,6 +1497,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev,
pr_debug("%s:-> %d\n", __func__, data->data.length); pr_debug("%s:-> %d\n", __func__, data->data.length);
return 0; return 0;
} }
#endif
/* SIOCGIWNICKN */ /* SIOCGIWNICKN */
static int gelic_wl_get_nick(struct net_device *net_dev, static int gelic_wl_get_nick(struct net_device *net_dev,
@ -1524,15 +1521,20 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
struct gelic_eurus_cmd *cmd; struct gelic_eurus_cmd *cmd;
struct iw_statistics *is; struct iw_statistics *is;
struct gelic_eurus_rssi_info *rssi; struct gelic_eurus_rssi_info *rssi;
void *buf;
pr_debug("%s: <-\n", __func__); pr_debug("%s: <-\n", __func__);
buf = (void *)__get_free_page(GFP_KERNEL);
if (!buf)
return NULL;
is = &wl->iwstat; is = &wl->iwstat;
memset(is, 0, sizeof(*is)); memset(is, 0, sizeof(*is));
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG, cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
wl->buf, sizeof(*rssi)); buf, sizeof(*rssi));
if (cmd && !cmd->status && !cmd->cmd_status) { if (cmd && !cmd->status && !cmd->cmd_status) {
rssi = wl->buf; rssi = buf;
is->qual.level = be16_to_cpu(rssi->rssi); is->qual.level = be16_to_cpu(rssi->rssi);
is->qual.updated = IW_QUAL_LEVEL_UPDATED | is->qual.updated = IW_QUAL_LEVEL_UPDATED |
IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
@ -1541,6 +1543,7 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
is->qual.updated = IW_QUAL_ALL_INVALID; is->qual.updated = IW_QUAL_ALL_INVALID;
kfree(cmd); kfree(cmd);
free_page((unsigned long)buf);
pr_debug("%s: ->\n", __func__); pr_debug("%s: ->\n", __func__);
return is; return is;
} }
@ -1548,10 +1551,13 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
/* /*
* scanning helpers * scanning helpers
*/ */
static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
u8 *essid, size_t essid_len)
{ {
struct gelic_eurus_cmd *cmd; struct gelic_eurus_cmd *cmd;
int ret = 0; int ret = 0;
void *buf = NULL;
size_t len;
pr_debug("%s: <- always=%d\n", __func__, always_scan); pr_debug("%s: <- always=%d\n", __func__, always_scan);
if (mutex_lock_interruptible(&wl->scan_lock)) if (mutex_lock_interruptible(&wl->scan_lock))
@ -1574,12 +1580,27 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
complete(&wl->scan_done); complete(&wl->scan_done);
goto out; goto out;
} }
/* ESSID scan ? */
if (essid_len && essid) {
buf = (void *)__get_free_page(GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out;
}
len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
memset(buf, 0, len);
memcpy(buf, essid, essid_len);
pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
} else
len = 0;
/* /*
* issue start scan request * issue start scan request
*/ */
wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING; wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN, cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
NULL, 0); buf, len);
if (!cmd || cmd->status || cmd->cmd_status) { if (!cmd || cmd->status || cmd->cmd_status) {
wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
complete(&wl->scan_done); complete(&wl->scan_done);
@ -1588,6 +1609,7 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
} }
kfree(cmd); kfree(cmd);
out: out:
free_page((unsigned long)buf);
mutex_unlock(&wl->scan_lock); mutex_unlock(&wl->scan_lock);
pr_debug("%s: ->\n", __func__); pr_debug("%s: ->\n", __func__);
return ret; return ret;
@ -1607,11 +1629,18 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
union iwreq_data data; union iwreq_data data;
unsigned long this_time = jiffies; unsigned long this_time = jiffies;
unsigned int data_len, i, found, r; unsigned int data_len, i, found, r;
void *buf;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
pr_debug("%s:start\n", __func__); pr_debug("%s:start\n", __func__);
mutex_lock(&wl->scan_lock); mutex_lock(&wl->scan_lock);
buf = (void *)__get_free_page(GFP_KERNEL);
if (!buf) {
pr_info("%s: scan buffer alloc failed\n", __func__);
goto out;
}
if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
/* /*
* stop() may be called while scanning, ignore result * stop() may be called while scanning, ignore result
@ -1622,7 +1651,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
} }
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN, cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
wl->buf, PAGE_SIZE); buf, PAGE_SIZE);
if (!cmd || cmd->status || cmd->cmd_status) { if (!cmd || cmd->status || cmd->cmd_status) {
wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
pr_info("%s:cmd failed\n", __func__); pr_info("%s:cmd failed\n", __func__);
@ -1649,7 +1678,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
} }
/* put them in the newtork_list */ /* put them in the newtork_list */
for (i = 0, scan_info_size = 0, scan_info = wl->buf; for (i = 0, scan_info_size = 0, scan_info = buf;
scan_info_size < data_len; scan_info_size < data_len;
i++, scan_info_size += be16_to_cpu(scan_info->size), i++, scan_info_size += be16_to_cpu(scan_info->size),
scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
@ -1726,6 +1755,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data, wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
NULL); NULL);
out: out:
free_page((unsigned long)buf);
complete(&wl->scan_done); complete(&wl->scan_done);
mutex_unlock(&wl->scan_lock); mutex_unlock(&wl->scan_lock);
pr_debug("%s:end\n", __func__); pr_debug("%s:end\n", __func__);
@ -1848,7 +1878,10 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
pr_debug("%s: <-\n", __func__); pr_debug("%s: <-\n", __func__);
/* we can assume no one should uses the buffer */ /* we can assume no one should uses the buffer */
wep = wl->buf; wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL);
if (!wep)
return -ENOMEM;
memset(wep, 0, sizeof(*wep)); memset(wep, 0, sizeof(*wep));
if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
@ -1898,6 +1931,7 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
kfree(cmd); kfree(cmd);
out: out:
free_page((unsigned long)wep);
pr_debug("%s: ->\n", __func__); pr_debug("%s: ->\n", __func__);
return ret; return ret;
} }
@ -1941,7 +1975,10 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
pr_debug("%s: <-\n", __func__); pr_debug("%s: <-\n", __func__);
/* we can assume no one should uses the buffer */ /* we can assume no one should uses the buffer */
wpa = wl->buf; wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL);
if (!wpa)
return -ENOMEM;
memset(wpa, 0, sizeof(*wpa)); memset(wpa, 0, sizeof(*wpa));
if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
@ -2000,6 +2037,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
else if (cmd->status || cmd->cmd_status) else if (cmd->status || cmd->cmd_status)
ret = -ENXIO; ret = -ENXIO;
kfree(cmd); kfree(cmd);
free_page((unsigned long)wpa);
pr_debug("%s: --> %d\n", __func__, ret); pr_debug("%s: --> %d\n", __func__, ret);
return ret; return ret;
} }
@ -2018,7 +2056,10 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
pr_debug("%s: <-\n", __func__); pr_debug("%s: <-\n", __func__);
/* do common config */ /* do common config */
common = wl->buf; common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL);
if (!common)
return -ENOMEM;
memset(common, 0, sizeof(*common)); memset(common, 0, sizeof(*common));
common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA); common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG); common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
@ -2104,6 +2145,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
pr_info("%s: connected\n", __func__); pr_info("%s: connected\n", __func__);
} }
out: out:
free_page((unsigned long)common);
pr_debug("%s: ->\n", __func__); pr_debug("%s: ->\n", __func__);
return ret; return ret;
} }
@ -2255,6 +2297,9 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
struct gelic_wl_scan_info *best_bss; struct gelic_wl_scan_info *best_bss;
int ret; int ret;
unsigned long irqflag;
u8 *essid;
size_t essid_len;
wl = container_of(work, struct gelic_wl_info, assoc_work.work); wl = container_of(work, struct gelic_wl_info, assoc_work.work);
@ -2263,7 +2308,19 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
goto out; goto out;
ret = gelic_wl_start_scan(wl, 0); spin_lock_irqsave(&wl->lock, irqflag);
if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
pr_debug("%s: assoc ESSID configured %s\n", __func__,
wl->essid);
essid = wl->essid;
essid_len = wl->essid_len;
} else {
essid = NULL;
essid_len = 0;
}
spin_unlock_irqrestore(&wl->lock, irqflag);
ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
if (ret == -ERESTARTSYS) { if (ret == -ERESTARTSYS) {
pr_debug("%s: scan start failed association\n", __func__); pr_debug("%s: scan start failed association\n", __func__);
schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/ schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
@ -2351,6 +2408,7 @@ static const iw_handler gelic_wl_wext_handler[] =
IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
}; };
#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
static struct iw_priv_args gelic_wl_private_args[] = static struct iw_priv_args gelic_wl_private_args[] =
{ {
{ {
@ -2372,15 +2430,18 @@ static const iw_handler gelic_wl_private_handler[] =
gelic_wl_priv_set_psk, gelic_wl_priv_set_psk,
gelic_wl_priv_get_psk, gelic_wl_priv_get_psk,
}; };
#endif
static const struct iw_handler_def gelic_wl_wext_handler_def = { static const struct iw_handler_def gelic_wl_wext_handler_def = {
.num_standard = ARRAY_SIZE(gelic_wl_wext_handler), .num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
.standard = gelic_wl_wext_handler, .standard = gelic_wl_wext_handler,
.get_wireless_stats = gelic_wl_get_wireless_stats, .get_wireless_stats = gelic_wl_get_wireless_stats,
#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
.num_private = ARRAY_SIZE(gelic_wl_private_handler), .num_private = ARRAY_SIZE(gelic_wl_private_handler),
.num_private_args = ARRAY_SIZE(gelic_wl_private_args), .num_private_args = ARRAY_SIZE(gelic_wl_private_args),
.private = gelic_wl_private_handler, .private = gelic_wl_private_handler,
.private_args = gelic_wl_private_args, .private_args = gelic_wl_private_args,
#endif
}; };
static struct net_device *gelic_wl_alloc(struct gelic_card *card) static struct net_device *gelic_wl_alloc(struct gelic_card *card)
@ -2446,16 +2507,9 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card)
BUILD_BUG_ON(PAGE_SIZE < BUILD_BUG_ON(PAGE_SIZE <
sizeof(struct gelic_eurus_scan_info) * sizeof(struct gelic_eurus_scan_info) *
GELIC_EURUS_MAX_SCAN); GELIC_EURUS_MAX_SCAN);
wl->buf = (void *)get_zeroed_page(GFP_KERNEL);
if (!wl->buf) {
pr_info("%s:buffer allocation failed\n", __func__);
goto fail_getpage;
}
pr_debug("%s:end\n", __func__); pr_debug("%s:end\n", __func__);
return netdev; return netdev;
fail_getpage:
destroy_workqueue(wl->event_queue);
fail_event_workqueue: fail_event_workqueue:
destroy_workqueue(wl->eurus_cmd_queue); destroy_workqueue(wl->eurus_cmd_queue);
fail_cmd_workqueue: fail_cmd_workqueue:
@ -2474,8 +2528,6 @@ static void gelic_wl_free(struct gelic_wl_info *wl)
pr_debug("%s: <-\n", __func__); pr_debug("%s: <-\n", __func__);
free_page((unsigned long)wl->buf);
pr_debug("%s: destroy queues\n", __func__); pr_debug("%s: destroy queues\n", __func__);
destroy_workqueue(wl->eurus_cmd_queue); destroy_workqueue(wl->eurus_cmd_queue);
destroy_workqueue(wl->event_queue); destroy_workqueue(wl->event_queue);

View File

@ -288,9 +288,6 @@ struct gelic_wl_info {
u8 active_bssid[ETH_ALEN]; /* associated bssid */ u8 active_bssid[ETH_ALEN]; /* associated bssid */
unsigned int essid_len; unsigned int essid_len;
/* buffer for hypervisor IO */
void *buf;
struct iw_public_data wireless_data; struct iw_public_data wireless_data;
struct iw_statistics iwstat; struct iw_statistics iwstat;
}; };

View File

@ -324,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) { for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
unsigned int entry = dirty_tx % priv->tx_ring_size; unsigned int entry = dirty_tx % priv->tx_ring_size;
u32 status = le32_to_cpu(priv->tx_ring[entry].status); u32 status = le32_to_cpu(priv->tx_ring[entry].status);
struct ieee80211_tx_status tx_status; struct ieee80211_tx_info *txi;
struct adm8211_tx_ring_info *info; struct adm8211_tx_ring_info *info;
struct sk_buff *skb; struct sk_buff *skb;
@ -334,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
info = &priv->tx_buffers[entry]; info = &priv->tx_buffers[entry];
skb = info->skb; skb = info->skb;
txi = IEEE80211_SKB_CB(skb);
/* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */ /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
pci_unmap_single(priv->pdev, info->mapping, pci_unmap_single(priv->pdev, info->mapping,
info->skb->len, PCI_DMA_TODEVICE); info->skb->len, PCI_DMA_TODEVICE);
memset(&tx_status, 0, sizeof(tx_status)); memset(&txi->status, 0, sizeof(txi->status));
skb_pull(skb, sizeof(struct adm8211_tx_hdr)); skb_pull(skb, sizeof(struct adm8211_tx_hdr));
memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
memcpy(&tx_status.control, &info->tx_control, if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
sizeof(tx_status.control));
if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
if (status & TDES0_STATUS_ES) if (status & TDES0_STATUS_ES)
tx_status.excessive_retries = 1; txi->status.excessive_retries = 1;
else else
tx_status.flags |= IEEE80211_TX_STATUS_ACK; txi->flags |= IEEE80211_TX_STAT_ACK;
} }
ieee80211_tx_status_irqsafe(dev, skb, &tx_status); ieee80211_tx_status_irqsafe(dev, skb);
info->skb = NULL; info->skb = NULL;
} }
@ -1638,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int
/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */ /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb, static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
u16 plcp_signal, u16 plcp_signal,
struct ieee80211_tx_control *control,
size_t hdrlen) size_t hdrlen)
{ {
struct adm8211_priv *priv = dev->priv; struct adm8211_priv *priv = dev->priv;
@ -1664,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
priv->tx_buffers[entry].skb = skb; priv->tx_buffers[entry].skb = skb;
priv->tx_buffers[entry].mapping = mapping; priv->tx_buffers[entry].mapping = mapping;
memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
priv->tx_buffers[entry].hdrlen = hdrlen; priv->tx_buffers[entry].hdrlen = hdrlen;
priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping); priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
@ -1685,18 +1682,18 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
} }
/* Put adm8211_tx_hdr on skb and transmit */ /* Put adm8211_tx_hdr on skb and transmit */
static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct adm8211_tx_hdr *txhdr; struct adm8211_tx_hdr *txhdr;
u16 fc; u16 fc;
size_t payload_len, hdrlen; size_t payload_len, hdrlen;
int plcp, dur, len, plcp_signal, short_preamble; int plcp, dur, len, plcp_signal, short_preamble;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
short_preamble = !!(control->tx_rate->flags & short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
IEEE80211_TXCTL_SHORT_PREAMBLE); plcp_signal = txrate->bitrate;
plcp_signal = control->tx_rate->bitrate;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
@ -1730,15 +1727,15 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
if (short_preamble) if (short_preamble)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
if (fc & IEEE80211_FCTL_PROTECTED) if (fc & IEEE80211_FCTL_PROTECTED)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE); txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
txhdr->retry_limit = control->retry_limit; txhdr->retry_limit = info->control.retry_limit;
adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen); adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
@ -2015,7 +2012,7 @@ static int adm8211_resume(struct pci_dev *pdev)
if (priv->mode != IEEE80211_IF_TYPE_INVALID) { if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
adm8211_start(dev); adm8211_start(dev);
ieee80211_start_queues(dev); ieee80211_wake_queues(dev);
} }
return 0; return 0;

View File

@ -443,7 +443,6 @@ struct adm8211_rx_ring_info {
struct adm8211_tx_ring_info { struct adm8211_tx_ring_info {
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t mapping; dma_addr_t mapping;
struct ieee80211_tx_control tx_control;
size_t hdrlen; size_t hdrlen;
}; };

View File

@ -167,8 +167,7 @@ static struct pci_driver ath5k_pci_driver = {
/* /*
* Prototypes - MAC 802.11 stack related functions * Prototypes - MAC 802.11 stack related functions
*/ */
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
struct ieee80211_tx_control *ctl);
static int ath5k_reset(struct ieee80211_hw *hw); static int ath5k_reset(struct ieee80211_hw *hw);
static int ath5k_start(struct ieee80211_hw *hw); static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw); static void ath5k_stop(struct ieee80211_hw *hw);
@ -196,8 +195,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_reset_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw);
static int ath5k_beacon_update(struct ieee80211_hw *hw, static int ath5k_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *skb, struct sk_buff *skb);
struct ieee80211_tx_control *ctl);
static struct ieee80211_ops ath5k_hw_ops = { static struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx, .tx = ath5k_tx,
@ -251,9 +249,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
static int ath5k_rxbuf_setup(struct ath5k_softc *sc, static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf); struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc, static int ath5k_txbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf, struct ath5k_buf *bf);
struct ieee80211_tx_control *ctl);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc, static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf) struct ath5k_buf *bf)
{ {
@ -289,8 +285,7 @@ static void ath5k_tx_processq(struct ath5k_softc *sc,
static void ath5k_tasklet_tx(unsigned long data); static void ath5k_tasklet_tx(unsigned long data);
/* Beacon handling */ /* Beacon handling */
static int ath5k_beacon_setup(struct ath5k_softc *sc, static int ath5k_beacon_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf, struct ath5k_buf *bf);
struct ieee80211_tx_control *ctl);
static void ath5k_beacon_send(struct ath5k_softc *sc); static void ath5k_beacon_send(struct ath5k_softc *sc);
static void ath5k_beacon_config(struct ath5k_softc *sc); static void ath5k_beacon_config(struct ath5k_softc *sc);
static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
@ -1295,36 +1290,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
} }
static int static int
ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
struct ieee80211_tx_control *ctl)
{ {
struct ath5k_hw *ah = sc->ah; struct ath5k_hw *ah = sc->ah;
struct ath5k_txq *txq = sc->txq; struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc; struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb; struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
int ret; int ret;
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
bf->ctl = *ctl;
/* XXX endianness */ /* XXX endianness */
bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (ctl->flags & IEEE80211_TXCTL_NO_ACK) if (info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK; flags |= AR5K_TXDESC_NOACK;
pktlen = skb->len; pktlen = skb->len;
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
keyidx = ctl->hw_key->hw_key_idx; keyidx = info->control.hw_key->hw_key_idx;
pktlen += ctl->icv_len; pktlen += info->control.icv_len;
} }
ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
(sc->power_level * 2), ctl->tx_rate->hw_value, (sc->power_level * 2),
ctl->retry_limit, keyidx, 0, flags, 0, 0); ieee80211_get_tx_rate(sc->hw, info)->hw_value,
info->control.retry_limit, keyidx, 0, flags, 0, 0);
if (ret) if (ret)
goto err_unmap; goto err_unmap;
@ -1599,7 +1594,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
sc->txqs[i].link); sc->txqs[i].link);
} }
} }
ieee80211_start_queues(sc->hw); /* XXX move to callers */ ieee80211_wake_queues(sc->hw); /* XXX move to callers */
for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
if (sc->txqs[i].setup) if (sc->txqs[i].setup)
@ -1926,11 +1921,11 @@ next:
static void static void
ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
{ {
struct ieee80211_tx_status txs = {};
struct ath5k_tx_status ts = {}; struct ath5k_tx_status ts = {};
struct ath5k_buf *bf, *bf0; struct ath5k_buf *bf, *bf0;
struct ath5k_desc *ds; struct ath5k_desc *ds;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_info *info;
int ret; int ret;
spin_lock(&txq->lock); spin_lock(&txq->lock);
@ -1950,24 +1945,25 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
} }
skb = bf->skb; skb = bf->skb;
info = IEEE80211_SKB_CB(skb);
bf->skb = NULL; bf->skb = NULL;
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
txs.control = bf->ctl; info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
if (unlikely(ts.ts_status)) { if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++; sc->ll_stats.dot11ACKFailureCount++;
if (ts.ts_status & AR5K_TXERR_XRETRY) if (ts.ts_status & AR5K_TXERR_XRETRY)
txs.excessive_retries = 1; info->status.excessive_retries = 1;
else if (ts.ts_status & AR5K_TXERR_FILT) else if (ts.ts_status & AR5K_TXERR_FILT)
txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
} else { } else {
txs.flags |= IEEE80211_TX_STATUS_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
txs.ack_signal = ts.ts_rssi; info->status.ack_signal = ts.ts_rssi;
} }
ieee80211_tx_status(sc->hw, skb, &txs); ieee80211_tx_status(sc->hw, skb);
sc->tx_stats[txq->qnum].count++; sc->tx_stats[txq->qnum].count++;
spin_lock(&sc->txbuflock); spin_lock(&sc->txbuflock);
@ -2004,10 +2000,10 @@ ath5k_tasklet_tx(unsigned long data)
* Setup the beacon frame for transmit. * Setup the beacon frame for transmit.
*/ */
static int static int
ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
struct ieee80211_tx_control *ctl)
{ {
struct sk_buff *skb = bf->skb; struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath5k_hw *ah = sc->ah; struct ath5k_hw *ah = sc->ah;
struct ath5k_desc *ds; struct ath5k_desc *ds;
int ret, antenna = 0; int ret, antenna = 0;
@ -2046,7 +2042,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb), ieee80211_get_hdrlen_from_skb(skb),
AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, ieee80211_get_tx_rate(sc->hw, info)->hw_value,
1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0); antenna, flags, 0, 0);
if (ret) if (ret)
goto err_unmap; goto err_unmap;
@ -2624,11 +2621,11 @@ ath5k_led_event(struct ath5k_softc *sc, int event)
\********************/ \********************/
static int static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct ath5k_softc *sc = hw->priv; struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf; struct ath5k_buf *bf;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
unsigned long flags; unsigned long flags;
int hdrlen; int hdrlen;
int pad; int pad;
@ -2654,13 +2651,13 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
memmove(skb->data, skb->data+pad, hdrlen); memmove(skb->data, skb->data+pad, hdrlen);
} }
sc->led_txrate = ctl->tx_rate->hw_value; sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
spin_lock_irqsave(&sc->txbuflock, flags); spin_lock_irqsave(&sc->txbuflock, flags);
if (list_empty(&sc->txbuf)) { if (list_empty(&sc->txbuf)) {
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
spin_unlock_irqrestore(&sc->txbuflock, flags); spin_unlock_irqrestore(&sc->txbuflock, flags);
ieee80211_stop_queue(hw, ctl->queue); ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
return -1; return -1;
} }
bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
@ -2672,7 +2669,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
bf->skb = skb; bf->skb = skb;
if (ath5k_txbuf_setup(sc, bf, ctl)) { if (ath5k_txbuf_setup(sc, bf)) {
bf->skb = NULL; bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags); spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf); list_add_tail(&bf->list, &sc->txbuf);
@ -3050,8 +3047,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
} }
static int static int
ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct ath5k_softc *sc = hw->priv; struct ath5k_softc *sc = hw->priv;
int ret; int ret;
@ -3067,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
ath5k_txbuf_free(sc, sc->bbuf); ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb; sc->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret) if (ret)
sc->bbuf->skb = NULL; sc->bbuf->skb = NULL;
else else

View File

@ -60,7 +60,6 @@ struct ath5k_buf {
dma_addr_t daddr; /* physical addr of desc */ dma_addr_t daddr; /* physical addr of desc */
struct sk_buff *skb; /* skbuff for buf */ struct sk_buff *skb; /* skbuff for buf */
dma_addr_t skbaddr;/* physical addr of skb data */ dma_addr_t skbaddr;/* physical addr of skb data */
struct ieee80211_tx_control ctl;
}; };
/* /*

View File

@ -422,6 +422,26 @@ enum {
B43_IRQ_RFKILL | \ B43_IRQ_RFKILL | \
B43_IRQ_TX_OK) B43_IRQ_TX_OK)
/* The firmware register to fetch the debug-IRQ reason from. */
#define B43_DEBUGIRQ_REASON_REG 63
/* Debug-IRQ reasons. */
#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */
#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */
#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */
#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */
#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */
/* The firmware register that contains the "marker" line. */
#define B43_MARKER_ID_REG 2
#define B43_MARKER_LINE_REG 3
/* The firmware register to fetch the panic reason from. */
#define B43_FWPANIC_REASON_REG 3
/* Firmware panic reason codes */
#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */
#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */
/* Device specific rate values. /* Device specific rate values.
* The actual values defined here are (rate_in_mbps * 2). * The actual values defined here are (rate_in_mbps * 2).
* Some code depends on this. Don't change it. */ * Some code depends on this. Don't change it. */
@ -733,7 +753,6 @@ struct b43_wl {
/* The beacon we are currently using (AP or IBSS mode). /* The beacon we are currently using (AP or IBSS mode).
* This beacon stuff is protected by the irq_lock. */ * This beacon stuff is protected by the irq_lock. */
struct sk_buff *current_beacon; struct sk_buff *current_beacon;
struct ieee80211_tx_control beacon_txctl;
bool beacon0_uploaded; bool beacon0_uploaded;
bool beacon1_uploaded; bool beacon1_uploaded;
struct work_struct beacon_update_trigger; struct work_struct beacon_update_trigger;
@ -766,6 +785,13 @@ struct b43_firmware {
u16 rev; u16 rev;
/* Firmware patchlevel */ /* Firmware patchlevel */
u16 patch; u16 patch;
/* Set to true, if we are using an opensource firmware. */
bool opensource;
/* Set to true, if the core needs a PCM firmware, but
* we failed to load one. This is always false for
* core rev > 10, as these don't need PCM firmware. */
bool pcm_request_failed;
}; };
/* Device (802.11 core) initialization status. */ /* Device (802.11 core) initialization status. */

View File

@ -1131,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
} }
static int dma_tx_fragment(struct b43_dmaring *ring, static int dma_tx_fragment(struct b43_dmaring *ring,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
const struct b43_dma_ops *ops = ring->ops; const struct b43_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header; u8 *header;
int slot, old_top_slot, old_used_slots; int slot, old_top_slot, old_used_slots;
int err; int err;
@ -1158,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
header = &(ring->txhdr_cache[slot * hdrsize]); header = &(ring->txhdr_cache[slot * hdrsize]);
cookie = generate_cookie(ring, slot); cookie = generate_cookie(ring, slot);
err = b43_generate_txhdr(ring->dev, header, err = b43_generate_txhdr(ring->dev, header,
skb->data, skb->len, ctl, cookie); skb->data, skb->len, info, cookie);
if (unlikely(err)) { if (unlikely(err)) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots; ring->used_slots = old_used_slots;
@ -1180,7 +1180,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
desc = ops->idx2desc(ring, slot, &meta); desc = ops->idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta)); memset(meta, 0, sizeof(*meta));
memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb; meta->skb = skb;
meta->is_last_fragment = 1; meta->is_last_fragment = 1;
@ -1210,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last /* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */ * mcast frame, so it can clear the more-data bit in it. */
b43_shm_write16(ring->dev, B43_SHM_SHARED, b43_shm_write16(ring->dev, B43_SHM_SHARED,
@ -1281,16 +1280,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
return ring; return ring;
} }
int b43_dma_tx(struct b43_wldev *dev, int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{ {
struct b43_dmaring *ring; struct b43_dmaring *ring;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast ring will be sent after the DTIM */ /* The multicast ring will be sent after the DTIM */
ring = dev->dma.tx_ring_mcast; ring = dev->dma.tx_ring_mcast;
/* Set the more-data bit. Ucode will clear it on /* Set the more-data bit. Ucode will clear it on
@ -1298,7 +1297,8 @@ int b43_dma_tx(struct b43_wldev *dev,
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else { } else {
/* Decide by priority where to put this frame. */ /* Decide by priority where to put this frame. */
ring = select_ring_by_priority(dev, ctl->queue); ring = select_ring_by_priority(
dev, skb_get_queue_mapping(skb));
} }
spin_lock_irqsave(&ring->lock, flags); spin_lock_irqsave(&ring->lock, flags);
@ -1316,9 +1316,9 @@ int b43_dma_tx(struct b43_wldev *dev,
/* Assign the queue number to the ring (if not already done before) /* Assign the queue number to the ring (if not already done before)
* so TX status handling can use it. The queue to ring mapping is * so TX status handling can use it. The queue to ring mapping is
* static, so we don't need to store it per frame. */ * static, so we don't need to store it per frame. */
ring->queue_prio = ctl->queue; ring->queue_prio = skb_get_queue_mapping(skb);
err = dma_tx_fragment(ring, skb, ctl); err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) { if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key /* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */ * anymore and must not transmit it unencrypted. */
@ -1334,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev,
if ((free_slots(ring) < SLOTS_PER_PACKET) || if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) { should_inject_overflow(ring)) {
/* This TX ring is full. */ /* This TX ring is full. */
ieee80211_stop_queue(dev->wl->hw, ctl->queue); ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
ring->stopped = 1; ring->stopped = 1;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@ -1377,13 +1377,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
b43_txhdr_size(dev), 1); b43_txhdr_size(dev), 1);
if (meta->is_last_fragment) { if (meta->is_last_fragment) {
B43_WARN_ON(!meta->skb); struct ieee80211_tx_info *info;
/* Call back to inform the ieee80211 subsystem about the
* status of the transmission. BUG_ON(!meta->skb);
* Some fields of txstat are already filled in dma_tx().
info = IEEE80211_SKB_CB(meta->skb);
memset(&info->status, 0, sizeof(info->status));
/*
* Call back to inform the ieee80211 subsystem about
* the status of the transmission.
*/ */
frame_succeed = b43_fill_txstatus_report( frame_succeed = b43_fill_txstatus_report(info, status);
&(meta->txstat), status);
#ifdef CONFIG_B43_DEBUG #ifdef CONFIG_B43_DEBUG
if (frame_succeed) if (frame_succeed)
ring->nr_succeed_tx_packets++; ring->nr_succeed_tx_packets++;
@ -1391,8 +1397,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
ring->nr_failed_tx_packets++; ring->nr_failed_tx_packets++;
ring->nr_total_packet_tries += status->frame_count; ring->nr_total_packet_tries += status->frame_count;
#endif /* DEBUG */ #endif /* DEBUG */
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
&(meta->txstat));
/* skb is freed by ieee80211_tx_status_irqsafe() */ /* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL; meta->skb = NULL;
} else { } else {

View File

@ -181,7 +181,6 @@ struct b43_dmadesc_meta {
dma_addr_t dmaaddr; dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */ /* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment; bool is_last_fragment;
struct ieee80211_tx_status txstat;
}; };
struct b43_dmaring; struct b43_dmaring;
@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats); struct ieee80211_tx_queue_stats *stats);
int b43_dma_tx(struct b43_wldev *dev, int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl); struct sk_buff *skb);
void b43_dma_handle_txstatus(struct b43_wldev *dev, void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status); const struct b43_txstatus *status);

View File

@ -1368,18 +1368,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
unsigned int rate; unsigned int rate;
u16 ctl; u16 ctl;
int antenna; int antenna;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
len = min((size_t) dev->wl->current_beacon->len, len = min((size_t) dev->wl->current_beacon->len,
0x200 - sizeof(struct b43_plcp_hdr6)); 0x200 - sizeof(struct b43_plcp_hdr6));
rate = dev->wl->beacon_txctl.tx_rate->hw_value; rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
b43_write_template_common(dev, (const u8 *)bcn, b43_write_template_common(dev, (const u8 *)bcn,
len, ram_offset, shm_size_offset, rate); len, ram_offset, shm_size_offset, rate);
/* Write the PHY TX control parameters. */ /* Write the PHY TX control parameters. */
antenna = b43_antenna_from_ieee80211(dev, antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
dev->wl->beacon_txctl.antenna_sel_tx);
antenna = b43_antenna_to_phyctl(antenna); antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */ /* We can't send beacons with short preamble. Would get PHY errors. */
@ -1430,11 +1430,17 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
i += ie_len + 2; i += ie_len + 2;
} }
if (!tim_found) { if (!tim_found) {
b43warn(dev->wl, "Did not find a valid TIM IE in " /*
"the beacon template packet. AP or IBSS operation " * If ucode wants to modify TIM do it behind the beacon, this
"may be broken.\n"); * will happen, for example, when doing mesh networking.
} else */
b43dbg(dev->wl, "Updated beacon template\n"); b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_TIMBPOS,
len + sizeof(struct b43_plcp_hdr6));
b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_DTIMPER, 0);
}
b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
} }
static void b43_write_probe_resp_plcp(struct b43_wldev *dev, static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
@ -1549,7 +1555,8 @@ static void handle_irq_beacon(struct b43_wldev *dev)
struct b43_wl *wl = dev->wl; struct b43_wl *wl = dev->wl;
u32 cmd, beacon0_valid, beacon1_valid; u32 cmd, beacon0_valid, beacon1_valid;
if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
!b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
return; return;
/* This is the bottom half of the asynchronous beacon update. */ /* This is the bottom half of the asynchronous beacon update. */
@ -1613,8 +1620,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
/* Asynchronously update the packet templates in template RAM. /* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */ * Locking: Requires wl->irq_lock to be locked. */
static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
const struct ieee80211_tx_control *txctl)
{ {
/* This is the top half of the ansynchronous beacon update. /* This is the top half of the ansynchronous beacon update.
* The bottom half is the beacon IRQ. * The bottom half is the beacon IRQ.
@ -1625,7 +1631,6 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon,
if (wl->current_beacon) if (wl->current_beacon)
dev_kfree_skb_any(wl->current_beacon); dev_kfree_skb_any(wl->current_beacon);
wl->current_beacon = beacon; wl->current_beacon = beacon;
memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl));
wl->beacon0_uploaded = 0; wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0; wl->beacon1_uploaded = 0;
queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
@ -1664,9 +1669,100 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
} }
static void b43_handle_firmware_panic(struct b43_wldev *dev)
{
u16 reason;
/* Read the register that contains the reason code for the panic. */
reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
switch (reason) {
default:
b43dbg(dev->wl, "The panic reason is unknown.\n");
/* fallthrough */
case B43_FWPANIC_DIE:
/* Do not restart the controller or firmware.
* The device is nonfunctional from now on.
* Restarting would result in this panic to trigger again,
* so we avoid that recursion. */
break;
case B43_FWPANIC_RESTART:
b43_controller_restart(dev, "Microcode panic");
break;
}
}
static void handle_irq_ucode_debug(struct b43_wldev *dev) static void handle_irq_ucode_debug(struct b43_wldev *dev)
{ {
//TODO unsigned int i, cnt;
u16 reason, marker_id, marker_line;
__le16 *buf;
/* The proprietary firmware doesn't have this IRQ. */
if (!dev->fw.opensource)
return;
/* Read the register that contains the reason code for this IRQ. */
reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
switch (reason) {
case B43_DEBUGIRQ_PANIC:
b43_handle_firmware_panic(dev);
break;
case B43_DEBUGIRQ_DUMP_SHM:
if (!B43_DEBUG)
break; /* Only with driver debugging enabled. */
buf = kmalloc(4096, GFP_ATOMIC);
if (!buf) {
b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
goto out;
}
for (i = 0; i < 4096; i += 2) {
u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
buf[i / 2] = cpu_to_le16(tmp);
}
b43info(dev->wl, "Shared memory dump:\n");
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
16, 2, buf, 4096, 1);
kfree(buf);
break;
case B43_DEBUGIRQ_DUMP_REGS:
if (!B43_DEBUG)
break; /* Only with driver debugging enabled. */
b43info(dev->wl, "Microcode register dump:\n");
for (i = 0, cnt = 0; i < 64; i++) {
u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
if (cnt == 0)
printk(KERN_INFO);
printk("r%02u: 0x%04X ", i, tmp);
cnt++;
if (cnt == 6) {
printk("\n");
cnt = 0;
}
}
printk("\n");
break;
case B43_DEBUGIRQ_MARKER:
if (!B43_DEBUG)
break; /* Only with driver debugging enabled. */
marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
B43_MARKER_ID_REG);
marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
B43_MARKER_LINE_REG);
b43info(dev->wl, "The firmware just executed the MARKER(%u) "
"at line number %u\n",
marker_id, marker_line);
break;
default:
b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
reason);
}
out:
/* Acknowledge the debug-IRQ, so the firmware can continue. */
b43_shm_write16(dev, B43_SHM_SCRATCH,
B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
} }
/* Interrupt handler bottom-half */ /* Interrupt handler bottom-half */
@ -1853,7 +1949,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
static int do_request_fw(struct b43_wldev *dev, static int do_request_fw(struct b43_wldev *dev,
const char *name, const char *name,
struct b43_firmware_file *fw) struct b43_firmware_file *fw,
bool silent)
{ {
char path[sizeof(modparam_fwpostfix) + 32]; char path[sizeof(modparam_fwpostfix) + 32];
const struct firmware *blob; const struct firmware *blob;
@ -1877,9 +1974,15 @@ static int do_request_fw(struct b43_wldev *dev,
"b43%s/%s.fw", "b43%s/%s.fw",
modparam_fwpostfix, name); modparam_fwpostfix, name);
err = request_firmware(&blob, path, dev->dev->dev); err = request_firmware(&blob, path, dev->dev->dev);
if (err) { if (err == -ENOENT) {
b43err(dev->wl, "Firmware file \"%s\" not found " if (!silent) {
"or load failed.\n", path); b43err(dev->wl, "Firmware file \"%s\" not found\n",
path);
}
return err;
} else if (err) {
b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
path, err);
return err; return err;
} }
if (blob->size < sizeof(struct b43_fw_header)) if (blob->size < sizeof(struct b43_fw_header))
@ -1930,7 +2033,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
filename = "ucode13"; filename = "ucode13";
else else
goto err_no_ucode; goto err_no_ucode;
err = do_request_fw(dev, filename, &fw->ucode); err = do_request_fw(dev, filename, &fw->ucode, 0);
if (err) if (err)
goto err_load; goto err_load;
@ -1941,8 +2044,13 @@ static int b43_request_firmware(struct b43_wldev *dev)
filename = NULL; filename = NULL;
else else
goto err_no_pcm; goto err_no_pcm;
err = do_request_fw(dev, filename, &fw->pcm); fw->pcm_request_failed = 0;
if (err) err = do_request_fw(dev, filename, &fw->pcm, 1);
if (err == -ENOENT) {
/* We did not find a PCM file? Not fatal, but
* core rev <= 10 must do without hwcrypto then. */
fw->pcm_request_failed = 1;
} else if (err)
goto err_load; goto err_load;
/* Get initvals */ /* Get initvals */
@ -1960,7 +2068,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
if ((rev >= 5) && (rev <= 10)) if ((rev >= 5) && (rev <= 10))
filename = "b0g0initvals5"; filename = "b0g0initvals5";
else if (rev >= 13) else if (rev >= 13)
filename = "lp0initvals13"; filename = "b0g0initvals13";
else else
goto err_no_initvals; goto err_no_initvals;
break; break;
@ -1973,7 +2081,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
default: default:
goto err_no_initvals; goto err_no_initvals;
} }
err = do_request_fw(dev, filename, &fw->initvals); err = do_request_fw(dev, filename, &fw->initvals, 0);
if (err) if (err)
goto err_load; goto err_load;
@ -2007,7 +2115,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
default: default:
goto err_no_initvals; goto err_no_initvals;
} }
err = do_request_fw(dev, filename, &fw->initvals_band); err = do_request_fw(dev, filename, &fw->initvals_band, 0);
if (err) if (err)
goto err_load; goto err_load;
@ -2124,14 +2232,28 @@ static int b43_upload_microcode(struct b43_wldev *dev)
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto error; goto error;
} }
b43info(dev->wl, "Loading firmware version %u.%u "
"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
fwrev, fwpatch,
(fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
(fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
dev->fw.rev = fwrev; dev->fw.rev = fwrev;
dev->fw.patch = fwpatch; dev->fw.patch = fwpatch;
dev->fw.opensource = (fwdate == 0xFFFF);
if (dev->fw.opensource) {
/* Patchlevel info is encoded in the "time" field. */
dev->fw.patch = fwtime;
b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n",
dev->fw.rev, dev->fw.patch,
dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : "");
} else {
b43info(dev->wl, "Loading firmware version %u.%u "
"(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
fwrev, fwpatch,
(fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
(fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
if (dev->fw.pcm_request_failed) {
b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
"Hardware accelerated cryptography is disabled.\n");
b43_print_fw_helptext(dev->wl, 0);
}
}
if (b43_is_old_txhdr_format(dev)) { if (b43_is_old_txhdr_format(dev)) {
b43warn(dev->wl, "You are using an old firmware image. " b43warn(dev->wl, "You are using an old firmware image. "
@ -2376,7 +2498,8 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
ctl &= ~B43_MACCTL_BEACPROMISC; ctl &= ~B43_MACCTL_BEACPROMISC;
ctl |= B43_MACCTL_INFRA; ctl |= B43_MACCTL_INFRA;
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
ctl |= B43_MACCTL_AP; ctl |= B43_MACCTL_AP;
else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
ctl &= ~B43_MACCTL_INFRA; ctl &= ~B43_MACCTL_INFRA;
@ -2813,8 +2936,7 @@ static int b43_rng_init(struct b43_wl *wl)
} }
static int b43_op_tx(struct ieee80211_hw *hw, static int b43_op_tx(struct ieee80211_hw *hw,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev; struct b43_wldev *dev = wl->current_dev;
@ -2836,9 +2958,9 @@ static int b43_op_tx(struct ieee80211_hw *hw,
err = -ENODEV; err = -ENODEV;
if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
if (b43_using_pio_transfers(dev)) if (b43_using_pio_transfers(dev))
err = b43_pio_tx(dev, skb, ctl); err = b43_pio_tx(dev, skb);
else else
err = b43_dma_tx(dev, skb, ctl); err = b43_dma_tx(dev, skb);
} }
read_unlock_irqrestore(&wl->tx_lock, flags); read_unlock_irqrestore(&wl->tx_lock, flags);
@ -3244,8 +3366,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
b43_set_rx_antenna(dev, antenna); b43_set_rx_antenna(dev, antenna);
/* Update templates for AP mode. */ /* Update templates for AP/mesh mode. */
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
b43_set_beacon_int(dev, conf->beacon_int); b43_set_beacon_int(dev, conf->beacon_int);
if (!!conf->radio_enabled != phy->radio_on) { if (!!conf->radio_enabled != phy->radio_on) {
@ -3296,6 +3419,13 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock; goto out_unlock;
if (dev->fw.pcm_request_failed) {
/* We don't have firmware for the crypto engine.
* Must use software-crypto. */
err = -EOPNOTSUPP;
goto out_unlock;
}
err = -EINVAL; err = -EINVAL;
switch (key->alg) { switch (key->alg) {
case ALG_WEP: case ALG_WEP:
@ -3426,13 +3556,12 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
else else
memset(wl->bssid, 0, ETH_ALEN); memset(wl->bssid, 0, ETH_ALEN);
if (b43_status(dev) >= B43_STAT_INITIALIZED) { if (b43_status(dev) >= B43_STAT_INITIALIZED) {
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
B43_WARN_ON(conf->type != wl->if_type);
b43_set_ssid(dev, conf->ssid, conf->ssid_len); b43_set_ssid(dev, conf->ssid, conf->ssid_len);
if (conf->beacon) { if (conf->beacon)
b43_update_templates(wl, conf->beacon, b43_update_templates(wl, conf->beacon);
conf->beacon_control);
}
} }
b43_write_mac_bssid_templates(dev); b43_write_mac_bssid_templates(dev);
} }
@ -3497,7 +3626,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
/* Start data flow (TX/RX). */ /* Start data flow (TX/RX). */
b43_mac_enable(dev); b43_mac_enable(dev);
b43_interrupt_enable(dev, dev->irq_savedstate); b43_interrupt_enable(dev, dev->irq_savedstate);
ieee80211_start_queues(dev->wl->hw);
/* Start maintainance work */ /* Start maintainance work */
b43_periodic_tasks_setup(dev); b43_periodic_tasks_setup(dev);
@ -3970,6 +4098,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
/* TODO: allow WDS/AP devices to coexist */ /* TODO: allow WDS/AP devices to coexist */
if (conf->type != IEEE80211_IF_TYPE_AP && if (conf->type != IEEE80211_IF_TYPE_AP &&
conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
conf->type != IEEE80211_IF_TYPE_STA && conf->type != IEEE80211_IF_TYPE_STA &&
conf->type != IEEE80211_IF_TYPE_WDS && conf->type != IEEE80211_IF_TYPE_WDS &&
conf->type != IEEE80211_IF_TYPE_IBSS) conf->type != IEEE80211_IF_TYPE_IBSS)
@ -4119,31 +4248,29 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);
struct sk_buff *beacon; struct sk_buff *beacon;
unsigned long flags; unsigned long flags;
struct ieee80211_tx_control txctl;
/* We could modify the existing beacon and set the aid bit in /* We could modify the existing beacon and set the aid bit in
* the TIM field, but that would probably require resizing and * the TIM field, but that would probably require resizing and
* moving of data within the beacon template. * moving of data within the beacon template.
* Simply request a new beacon and let mac80211 do the hard work. */ * Simply request a new beacon and let mac80211 do the hard work. */
beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); beacon = ieee80211_beacon_get(hw, wl->vif);
if (unlikely(!beacon)) if (unlikely(!beacon))
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&wl->irq_lock, flags); spin_lock_irqsave(&wl->irq_lock, flags);
b43_update_templates(wl, beacon, &txctl); b43_update_templates(wl, beacon);
spin_unlock_irqrestore(&wl->irq_lock, flags); spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0; return 0;
} }
static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *beacon, struct sk_buff *beacon)
struct ieee80211_tx_control *ctl)
{ {
struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wl *wl = hw_to_b43_wl(hw);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&wl->irq_lock, flags); spin_lock_irqsave(&wl->irq_lock, flags);
b43_update_templates(wl, beacon, ctl); b43_update_templates(wl, beacon);
spin_unlock_irqrestore(&wl->irq_lock, flags); spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0; return 0;

View File

@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
} }
static int pio_tx_frame(struct b43_pio_txqueue *q, static int pio_tx_frame(struct b43_pio_txqueue *q,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct b43_pio_txpacket *pack; struct b43_pio_txpacket *pack;
struct b43_txhdr txhdr; struct b43_txhdr txhdr;
u16 cookie; u16 cookie;
int err; int err;
unsigned int hdrlen; unsigned int hdrlen;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
B43_WARN_ON(list_empty(&q->packets_list)); B43_WARN_ON(list_empty(&q->packets_list));
pack = list_entry(q->packets_list.next, pack = list_entry(q->packets_list.next,
struct b43_pio_txpacket, list); struct b43_pio_txpacket, list);
memset(&pack->txstat, 0, sizeof(pack->txstat));
memcpy(&pack->txstat.control, ctl, sizeof(*ctl));
cookie = generate_cookie(q, pack); cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(q->dev); hdrlen = b43_txhdr_size(q->dev);
err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
skb->len, ctl, cookie); skb->len, info, cookie);
if (err) if (err)
return err; return err;
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last /* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */ * mcast frame, so it can clear the more-data bit in it. */
b43_shm_write16(q->dev, B43_SHM_SHARED, b43_shm_write16(q->dev, B43_SHM_SHARED,
@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
return 0; return 0;
} }
int b43_pio_tx(struct b43_wldev *dev, int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{ {
struct b43_pio_txqueue *q; struct b43_pio_txqueue *q;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
unsigned long flags; unsigned long flags;
unsigned int hdrlen, total_len; unsigned int hdrlen, total_len;
int err = 0; int err = 0;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast queue will be sent after the DTIM. */ /* The multicast queue will be sent after the DTIM. */
q = dev->pio.tx_queue_mcast; q = dev->pio.tx_queue_mcast;
/* Set the frame More-Data bit. Ucode will clear it /* Set the frame More-Data bit. Ucode will clear it
@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev,
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else { } else {
/* Decide by priority where to put this frame. */ /* Decide by priority where to put this frame. */
q = select_queue_by_priority(dev, ctl->queue); q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
} }
spin_lock_irqsave(&q->lock, flags); spin_lock_irqsave(&q->lock, flags);
@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev,
if (total_len > (q->buffer_size - q->buffer_used)) { if (total_len > (q->buffer_size - q->buffer_used)) {
/* Not enough memory on the queue. */ /* Not enough memory on the queue. */
err = -EBUSY; err = -EBUSY;
ieee80211_stop_queue(dev->wl->hw, ctl->queue); ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
q->stopped = 1; q->stopped = 1;
goto out_unlock; goto out_unlock;
} }
@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev,
/* Assign the queue number to the ring (if not already done before) /* Assign the queue number to the ring (if not already done before)
* so TX status handling can use it. The mac80211-queue to b43-queue * so TX status handling can use it. The mac80211-queue to b43-queue
* mapping is static, so we don't need to store it per frame. */ * mapping is static, so we don't need to store it per frame. */
q->queue_prio = ctl->queue; q->queue_prio = skb_get_queue_mapping(skb);
err = pio_tx_frame(q, skb, ctl); err = pio_tx_frame(q, skb);
if (unlikely(err == -ENOKEY)) { if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key /* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */ * anymore and must not transmit it unencrypted. */
@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev,
if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
(q->free_packet_slots == 0)) { (q->free_packet_slots == 0)) {
/* The queue is full. */ /* The queue is full. */
ieee80211_stop_queue(dev->wl->hw, ctl->queue); ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
q->stopped = 1; q->stopped = 1;
} }
@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
struct b43_pio_txqueue *q; struct b43_pio_txqueue *q;
struct b43_pio_txpacket *pack = NULL; struct b43_pio_txpacket *pack = NULL;
unsigned int total_len; unsigned int total_len;
struct ieee80211_tx_info *info;
q = parse_cookie(dev, status->cookie, &pack); q = parse_cookie(dev, status->cookie, &pack);
if (unlikely(!q)) if (unlikely(!q))
@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
spin_lock(&q->lock); /* IRQs are already disabled. */ spin_lock(&q->lock); /* IRQs are already disabled. */
b43_fill_txstatus_report(&(pack->txstat), status); info = (void *)pack->skb;
memset(&info->status, 0, sizeof(info->status));
b43_fill_txstatus_report(info, status);
total_len = pack->skb->len + b43_txhdr_size(dev); total_len = pack->skb->len + b43_txhdr_size(dev);
total_len = roundup(total_len, 4); total_len = roundup(total_len, 4);
q->buffer_used -= total_len; q->buffer_used -= total_len;
q->free_packet_slots += 1; q->free_packet_slots += 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb);
&(pack->txstat));
pack->skb = NULL; pack->skb = NULL;
list_add(&pack->list, &q->packets_list); list_add(&pack->list, &q->packets_list);

View File

@ -62,8 +62,6 @@ struct b43_pio_txpacket {
struct b43_pio_txqueue *queue; struct b43_pio_txqueue *queue;
/* The TX data packet. */ /* The TX data packet. */
struct sk_buff *skb; struct sk_buff *skb;
/* The status meta data. */
struct ieee80211_tx_status txstat;
/* Index in the (struct b43_pio_txqueue)->packets array. */ /* Index in the (struct b43_pio_txqueue)->packets array. */
u8 index; u8 index;
@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev);
void b43_pio_stop(struct b43_wldev *dev); void b43_pio_stop(struct b43_wldev *dev);
void b43_pio_free(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev);
int b43_pio_tx(struct b43_wldev *dev, int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb);
struct sk_buff *skb, struct ieee80211_tx_control *ctl);
void b43_pio_handle_txstatus(struct b43_wldev *dev, void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status); const struct b43_txstatus *status);
void b43_pio_get_tx_stats(struct b43_wldev *dev, void b43_pio_get_tx_stats(struct b43_wldev *dev,
@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev)
{ {
} }
static inline int b43_pio_tx(struct b43_wldev *dev, static inline int b43_pio_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
return 0; return 0;
} }

View File

@ -185,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 *_txhdr, u8 *_txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, const struct ieee80211_tx_info *info,
u16 cookie) u16 cookie)
{ {
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy; const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr = const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data; (const struct ieee80211_hdr *)fragment_data;
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
u16 fctl = le16_to_cpu(wlhdr->frame_control); u16 fctl = le16_to_cpu(wlhdr->frame_control);
struct ieee80211_rate *fbrate; struct ieee80211_rate *fbrate;
u8 rate, rate_fb; u8 rate, rate_fb;
@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u32 mac_ctl = 0; u32 mac_ctl = 0;
u16 phy_ctl = 0; u16 phy_ctl = 0;
u8 extra_ft = 0; u8 extra_ft = 0;
struct ieee80211_rate *txrate;
memset(txhdr, 0, sizeof(*txhdr)); memset(txhdr, 0, sizeof(*txhdr));
WARN_ON(!txctl->tx_rate); txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
rate_ofdm = b43_is_ofdm_rate(rate); rate_ofdm = b43_is_ofdm_rate(rate);
fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;
rate_fb = fbrate->hw_value; rate_fb = fbrate->hw_value;
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
@ -227,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev,
* use the original dur_id field. */ * use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id; txhdr->dur_fb = wlhdr->duration_id;
} else { } else {
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txhdr->dur_fb = ieee80211_generic_frame_duration(
txctl->vif, dev->wl->hw, info->control.vif, fragment_len, fbrate);
fragment_len,
fbrate);
} }
plcp_fragment_len = fragment_len + FCS_LEN; plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) { if (use_encryption) {
u8 key_idx = txctl->hw_key->hw_key_idx; u8 key_idx = info->control.hw_key->hw_key_idx;
struct b43_key *key; struct b43_key *key;
int wlhdr_len; int wlhdr_len;
size_t iv_len; size_t iv_len;
@ -253,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
} }
/* Hardware appends ICV. */ /* Hardware appends ICV. */
plcp_fragment_len += txctl->icv_len; plcp_fragment_len += info->control.icv_len;
key_idx = b43_kidx_to_fw(dev, key_idx); key_idx = b43_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
@ -261,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TXH_MAC_KEYALG; B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl); wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t) txctl->iv_len, iv_len = min((size_t) info->control.iv_len,
ARRAY_SIZE(txhdr->iv)); ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
} }
@ -292,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,
phy_ctl |= B43_TXH_PHY_ENC_OFDM; phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else else
phy_ctl |= B43_TXH_PHY_ENC_CCK; phy_ctl |= B43_TXH_PHY_ENC_CCK;
if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL; phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
case 0: /* Default */ case 0: /* Default */
phy_ctl |= B43_TXH_PHY_ANT01AUTO; phy_ctl |= B43_TXH_PHY_ANT01AUTO;
break; break;
@ -316,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,
} }
/* MAC control */ /* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK; mac_ctl |= B43_TXH_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43_TXH_MAC_HWSEQ; mac_ctl |= B43_TXH_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43_TXH_MAC_STMSDU; mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A) if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TXH_MAC_5GHZ; mac_ctl |= B43_TXH_MAC_5GHZ;
if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
mac_ctl |= B43_TXH_MAC_LONGFRAME; mac_ctl |= B43_TXH_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */ /* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
(txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
unsigned int len; unsigned int len;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb; int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm; int rts_rate_ofdm, rts_rate_fb_ofdm;
struct b43_plcp_hdr6 *plcp; struct b43_plcp_hdr6 *plcp;
struct ieee80211_rate *rts_cts_rate;
WARN_ON(!txctl->rts_cts_rate); rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
struct ieee80211_cts *cts; struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) { if (b43_is_old_txhdr_format(dev)) {
@ -353,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
cts = (struct ieee80211_cts *) cts = (struct ieee80211_cts *)
(txhdr->new_format.rts_frame); (txhdr->new_format.rts_frame);
} }
ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len, fragment_data, fragment_len,
txctl, cts); info, cts);
mac_ctl |= B43_TXH_MAC_SENDCTS; mac_ctl |= B43_TXH_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts); len = sizeof(struct ieee80211_cts);
} else { } else {
@ -368,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
rts = (struct ieee80211_rts *) rts = (struct ieee80211_rts *)
(txhdr->new_format.rts_frame); (txhdr->new_format.rts_frame);
} }
ieee80211_rts_get(dev->wl->hw, txctl->vif, ieee80211_rts_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len, fragment_data, fragment_len,
txctl, rts); info, rts);
mac_ctl |= B43_TXH_MAC_SENDRTS; mac_ctl |= B43_TXH_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts); len = sizeof(struct ieee80211_rts);
} }
@ -684,27 +685,27 @@ void b43_handle_txstatus(struct b43_wldev *dev,
/* Fill out the mac80211 TXstatus report based on the b43-specific /* Fill out the mac80211 TXstatus report based on the b43-specific
* txstatus report data. This returns a boolean whether the frame was * txstatus report data. This returns a boolean whether the frame was
* successfully transmitted. */ * successfully transmitted. */
bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status) const struct b43_txstatus *status)
{ {
bool frame_success = 1; bool frame_success = 1;
if (status->acked) { if (status->acked) {
/* The frame was ACKed. */ /* The frame was ACKed. */
report->flags |= IEEE80211_TX_STATUS_ACK; report->flags |= IEEE80211_TX_STAT_ACK;
} else { } else {
/* The frame was not ACKed... */ /* The frame was not ACKed... */
if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ...but we expected an ACK. */ /* ...but we expected an ACK. */
frame_success = 0; frame_success = 0;
report->excessive_retries = 1; report->status.excessive_retries = 1;
} }
} }
if (status->frame_count == 0) { if (status->frame_count == 0) {
/* The frame was not transmitted at all. */ /* The frame was not transmitted at all. */
report->retry_count = 0; report->status.retry_count = 0;
} else } else
report->retry_count = status->frame_count - 1; report->status.retry_count = status->frame_count - 1;
return frame_success; return frame_success;
} }

View File

@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr, u8 * txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, u16 cookie); const struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */ /* Transmit Status */
struct b43_txstatus { struct b43_txstatus {
@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
void b43_handle_txstatus(struct b43_wldev *dev, void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status); const struct b43_txstatus *status);
bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status); const struct b43_txstatus *status);
void b43_tx_suspend(struct b43_wldev *dev); void b43_tx_suspend(struct b43_wldev *dev);

View File

@ -1205,10 +1205,10 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
} }
static int dma_tx_fragment(struct b43legacy_dmaring *ring, static int dma_tx_fragment(struct b43legacy_dmaring *ring,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
const struct b43legacy_dma_ops *ops = ring->ops; const struct b43legacy_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header; u8 *header;
int slot, old_top_slot, old_used_slots; int slot, old_top_slot, old_used_slots;
int err; int err;
@ -1231,7 +1231,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
header = &(ring->txhdr_cache[slot * sizeof( header = &(ring->txhdr_cache[slot * sizeof(
struct b43legacy_txhdr_fw3)]); struct b43legacy_txhdr_fw3)]);
err = b43legacy_generate_txhdr(ring->dev, header, err = b43legacy_generate_txhdr(ring->dev, header,
skb->data, skb->len, ctl, skb->data, skb->len, info,
generate_cookie(ring, slot)); generate_cookie(ring, slot));
if (unlikely(err)) { if (unlikely(err)) {
ring->current_slot = old_top_slot; ring->current_slot = old_top_slot;
@ -1255,7 +1255,6 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
desc = ops->idx2desc(ring, slot, &meta); desc = ops->idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta)); memset(meta, 0, sizeof(*meta));
memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb; meta->skb = skb;
meta->is_last_fragment = 1; meta->is_last_fragment = 1;
@ -1323,14 +1322,13 @@ int should_inject_overflow(struct b43legacy_dmaring *ring)
} }
int b43legacy_dma_tx(struct b43legacy_wldev *dev, int b43legacy_dma_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct b43legacy_dmaring *ring; struct b43legacy_dmaring *ring;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
ring = priority_to_txring(dev, ctl->queue); ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
spin_lock_irqsave(&ring->lock, flags); spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx); B43legacy_WARN_ON(!ring->tx);
if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@ -1343,7 +1341,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
* That would be a mac80211 bug. */ * That would be a mac80211 bug. */
B43legacy_BUG_ON(ring->stopped); B43legacy_BUG_ON(ring->stopped);
err = dma_tx_fragment(ring, skb, ctl); err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) { if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key /* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */ * anymore and must not transmit it unencrypted. */
@ -1401,26 +1399,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
1); 1);
if (meta->is_last_fragment) { if (meta->is_last_fragment) {
B43legacy_WARN_ON(!meta->skb); struct ieee80211_tx_info *info;
BUG_ON(!meta->skb);
info = IEEE80211_SKB_CB(meta->skb);
/* Call back to inform the ieee80211 subsystem about the /* Call back to inform the ieee80211 subsystem about the
* status of the transmission. * status of the transmission.
* Some fields of txstat are already filled in dma_tx(). * Some fields of txstat are already filled in dma_tx().
*/ */
memset(&info->status, 0, sizeof(info->status));
if (status->acked) { if (status->acked) {
meta->txstat.flags |= IEEE80211_TX_STATUS_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
} else { } else {
if (!(meta->txstat.control.flags if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
& IEEE80211_TXCTL_NO_ACK)) info->status.excessive_retries = 1;
meta->txstat.excessive_retries = 1;
} }
if (status->frame_count == 0) { if (status->frame_count == 0) {
/* The frame was not transmitted at all. */ /* The frame was not transmitted at all. */
meta->txstat.retry_count = 0; info->status.retry_count = 0;
} else } else
meta->txstat.retry_count = status->frame_count info->status.retry_count = status->frame_count
- 1; - 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
&(meta->txstat));
/* skb is freed by ieee80211_tx_status_irqsafe() */ /* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL; meta->skb = NULL;
} else { } else {

View File

@ -195,7 +195,6 @@ struct b43legacy_dmadesc_meta {
dma_addr_t dmaaddr; dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */ /* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment; bool is_last_fragment;
struct ieee80211_tx_status txstat;
}; };
struct b43legacy_dmaring; struct b43legacy_dmaring;
@ -297,8 +296,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
struct ieee80211_tx_queue_stats *stats); struct ieee80211_tx_queue_stats *stats);
int b43legacy_dma_tx(struct b43legacy_wldev *dev, int b43legacy_dma_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb);
struct ieee80211_tx_control *ctl);
void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status); const struct b43legacy_txstatus *status);
@ -323,8 +321,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
} }
static inline static inline
int b43legacy_dma_tx(struct b43legacy_wldev *dev, int b43legacy_dma_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
return 0; return 0;
} }

View File

@ -2358,8 +2358,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
} }
static int b43legacy_op_tx(struct ieee80211_hw *hw, static int b43legacy_op_tx(struct ieee80211_hw *hw,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev = wl->current_dev; struct b43legacy_wldev *dev = wl->current_dev;
@ -2373,10 +2372,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw,
/* DMA-TX is done without a global lock. */ /* DMA-TX is done without a global lock. */
if (b43legacy_using_pio(dev)) { if (b43legacy_using_pio(dev)) {
spin_lock_irqsave(&wl->irq_lock, flags); spin_lock_irqsave(&wl->irq_lock, flags);
err = b43legacy_pio_tx(dev, skb, ctl); err = b43legacy_pio_tx(dev, skb);
spin_unlock_irqrestore(&wl->irq_lock, flags); spin_unlock_irqrestore(&wl->irq_lock, flags);
} else } else
err = b43legacy_dma_tx(dev, skb, ctl); err = b43legacy_dma_tx(dev, skb);
out: out:
if (unlikely(err)) if (unlikely(err))
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
@ -2794,7 +2793,6 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
/* Start data flow (TX/RX) */ /* Start data flow (TX/RX) */
b43legacy_mac_enable(dev); b43legacy_mac_enable(dev);
b43legacy_interrupt_enable(dev, dev->irq_savedstate); b43legacy_interrupt_enable(dev, dev->irq_savedstate);
ieee80211_start_queues(dev->wl->hw);
/* Start maintenance work */ /* Start maintenance work */
b43legacy_periodic_tasks_setup(dev); b43legacy_periodic_tasks_setup(dev);
@ -3410,7 +3408,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
* field, but that would probably require resizing and moving of data * field, but that would probably require resizing and moving of data
* within the beacon template. Simply request a new beacon and let * within the beacon template. Simply request a new beacon and let
* mac80211 do the hard work. */ * mac80211 do the hard work. */
beacon = ieee80211_beacon_get(hw, wl->vif, NULL); beacon = ieee80211_beacon_get(hw, wl->vif);
if (unlikely(!beacon)) if (unlikely(!beacon))
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&wl->irq_lock, flags); spin_lock_irqsave(&wl->irq_lock, flags);
@ -3421,8 +3419,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
} }
static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw, static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *beacon, struct sk_buff *beacon)
struct ieee80211_tx_control *ctl)
{ {
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
unsigned long flags; unsigned long flags;

View File

@ -196,7 +196,7 @@ static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0); B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
err = b43legacy_generate_txhdr(queue->dev, err = b43legacy_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len, txhdr, skb->data, skb->len,
&packet->txstat.control, IEEE80211_SKB_CB(skb),
generate_cookie(queue, packet)); generate_cookie(queue, packet));
if (err) if (err)
return err; return err;
@ -463,8 +463,7 @@ err_destroy0:
} }
int b43legacy_pio_tx(struct b43legacy_wldev *dev, int b43legacy_pio_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct b43legacy_pioqueue *queue = dev->pio.queue1; struct b43legacy_pioqueue *queue = dev->pio.queue1;
struct b43legacy_pio_txpacket *packet; struct b43legacy_pio_txpacket *packet;
@ -476,9 +475,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev,
list); list);
packet->skb = skb; packet->skb = skb;
memset(&packet->txstat, 0, sizeof(packet->txstat));
memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
list_move_tail(&packet->list, &queue->txqueue); list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--; queue->nr_txfree--;
queue->nr_tx_packets++; queue->nr_tx_packets++;
@ -494,6 +490,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
{ {
struct b43legacy_pioqueue *queue; struct b43legacy_pioqueue *queue;
struct b43legacy_pio_txpacket *packet; struct b43legacy_pio_txpacket *packet;
struct ieee80211_tx_info *info;
queue = parse_cookie(dev, status->cookie, &packet); queue = parse_cookie(dev, status->cookie, &packet);
B43legacy_WARN_ON(!queue); B43legacy_WARN_ON(!queue);
@ -505,11 +502,13 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
queue->tx_devq_used -= (packet->skb->len + queue->tx_devq_used -= (packet->skb->len +
sizeof(struct b43legacy_txhdr_fw3)); sizeof(struct b43legacy_txhdr_fw3));
info = IEEE80211_SKB_CB(packet->skb);
memset(&info->status, 0, sizeof(info->status));
if (status->acked) if (status->acked)
packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
packet->txstat.retry_count = status->frame_count - 1; info->status.retry_count = status->frame_count - 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
&(packet->txstat));
packet->skb = NULL; packet->skb = NULL;
free_txpacket(packet, 1); free_txpacket(packet, 1);

View File

@ -41,7 +41,6 @@ struct b43legacy_xmitstatus;
struct b43legacy_pio_txpacket { struct b43legacy_pio_txpacket {
struct b43legacy_pioqueue *queue; struct b43legacy_pioqueue *queue;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_status txstat;
struct list_head list; struct list_head list;
}; };
@ -104,8 +103,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev);
void b43legacy_pio_free(struct b43legacy_wldev *dev); void b43legacy_pio_free(struct b43legacy_wldev *dev);
int b43legacy_pio_tx(struct b43legacy_wldev *dev, int b43legacy_pio_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb);
struct ieee80211_tx_control *ctl);
void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status); const struct b43legacy_txstatus *status);
void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev, void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
@ -132,8 +130,7 @@ void b43legacy_pio_free(struct b43legacy_wldev *dev)
} }
static inline static inline
int b43legacy_pio_tx(struct b43legacy_wldev *dev, int b43legacy_pio_tx(struct b43legacy_wldev *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
return 0; return 0;
} }

View File

@ -188,11 +188,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
struct b43legacy_txhdr_fw3 *txhdr, struct b43legacy_txhdr_fw3 *txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, const struct ieee80211_tx_info *info,
u16 cookie) u16 cookie)
{ {
const struct ieee80211_hdr *wlhdr; const struct ieee80211_hdr *wlhdr;
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
u16 fctl; u16 fctl;
u8 rate; u8 rate;
struct ieee80211_rate *rate_fb; struct ieee80211_rate *rate_fb;
@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
unsigned int plcp_fragment_len; unsigned int plcp_fragment_len;
u32 mac_ctl = 0; u32 mac_ctl = 0;
u16 phy_ctl = 0; u16 phy_ctl = 0;
struct ieee80211_rate *tx_rate;
wlhdr = (const struct ieee80211_hdr *)fragment_data; wlhdr = (const struct ieee80211_hdr *)fragment_data;
fctl = le16_to_cpu(wlhdr->frame_control); fctl = le16_to_cpu(wlhdr->frame_control);
memset(txhdr, 0, sizeof(*txhdr)); memset(txhdr, 0, sizeof(*txhdr));
rate = txctl->tx_rate->hw_value; tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info);
rate = tx_rate->hw_value;
rate_ofdm = b43legacy_is_ofdm_rate(rate); rate_ofdm = b43legacy_is_ofdm_rate(rate);
rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate;
rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
txhdr->mac_frame_ctl = wlhdr->frame_control; txhdr->mac_frame_ctl = wlhdr->frame_control;
@ -225,14 +228,14 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
txhdr->dur_fb = wlhdr->duration_id; txhdr->dur_fb = wlhdr->duration_id;
} else { } else {
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
txctl->vif, info->control.vif,
fragment_len, fragment_len,
rate_fb); rate_fb);
} }
plcp_fragment_len = fragment_len + FCS_LEN; plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) { if (use_encryption) {
u8 key_idx = txctl->hw_key->hw_key_idx; u8 key_idx = info->control.hw_key->hw_key_idx;
struct b43legacy_key *key; struct b43legacy_key *key;
int wlhdr_len; int wlhdr_len;
size_t iv_len; size_t iv_len;
@ -242,7 +245,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
if (key->enabled) { if (key->enabled) {
/* Hardware appends ICV. */ /* Hardware appends ICV. */
plcp_fragment_len += txctl->icv_len; plcp_fragment_len += info->control.icv_len;
key_idx = b43legacy_kidx_to_fw(dev, key_idx); key_idx = b43legacy_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
@ -251,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
B43legacy_TX4_MAC_KEYALG_SHIFT) & B43legacy_TX4_MAC_KEYALG_SHIFT) &
B43legacy_TX4_MAC_KEYALG; B43legacy_TX4_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl); wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t)txctl->iv_len, iv_len = min((size_t)info->control.iv_len,
ARRAY_SIZE(txhdr->iv)); ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
} else { } else {
@ -275,7 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
phy_ctl |= B43legacy_TX4_PHY_OFDM; phy_ctl |= B43legacy_TX4_PHY_OFDM;
if (dev->short_preamble) if (dev->short_preamble)
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
switch (txctl->antenna_sel_tx) { switch (info->antenna_sel_tx) {
case 0: case 0:
phy_ctl |= B43legacy_TX4_PHY_ANTLAST; phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
break; break;
@ -290,21 +293,21 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
} }
/* MAC control */ /* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43legacy_TX4_MAC_ACK; mac_ctl |= B43legacy_TX4_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43legacy_TX4_MAC_HWSEQ; mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43legacy_TX4_MAC_STMSDU; mac_ctl |= B43legacy_TX4_MAC_STMSDU;
if (rate_fb_ofdm) if (rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */ /* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
(txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
unsigned int len; unsigned int len;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
int rts_rate; int rts_rate;
@ -312,26 +315,26 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
int rts_rate_ofdm; int rts_rate_ofdm;
int rts_rate_fb_ofdm; int rts_rate_fb_ofdm;
rts_rate = txctl->rts_cts_rate->hw_value; rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value;
rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
if (rts_rate_fb_ofdm) if (rts_rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
ieee80211_ctstoself_get(dev->wl->hw, ieee80211_ctstoself_get(dev->wl->hw,
txctl->vif, info->control.vif,
fragment_data, fragment_data,
fragment_len, txctl, fragment_len, info,
(struct ieee80211_cts *) (struct ieee80211_cts *)
(txhdr->rts_frame)); (txhdr->rts_frame));
mac_ctl |= B43legacy_TX4_MAC_SENDCTS; mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts); len = sizeof(struct ieee80211_cts);
} else { } else {
ieee80211_rts_get(dev->wl->hw, ieee80211_rts_get(dev->wl->hw,
txctl->vif, info->control.vif,
fragment_data, fragment_len, txctl, fragment_data, fragment_len, info,
(struct ieee80211_rts *) (struct ieee80211_rts *)
(txhdr->rts_frame)); (txhdr->rts_frame));
mac_ctl |= B43legacy_TX4_MAC_SENDRTS; mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
@ -362,12 +365,12 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr, u8 *txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, const struct ieee80211_tx_info *info,
u16 cookie) u16 cookie)
{ {
return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
fragment_data, fragment_len, fragment_data, fragment_len,
txctl, cookie); info, cookie);
} }
static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,

View File

@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
u8 *txhdr, u8 *txhdr,
const unsigned char *fragment_data, const unsigned char *fragment_data,
unsigned int fragment_len, unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, const struct ieee80211_tx_info *info,
u16 cookie); u16 cookie);

View File

@ -445,8 +445,7 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
*/ */
static void rs_tx_status(void *priv_rate, static void rs_tx_status(void *priv_rate,
struct net_device *dev, struct net_device *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_status *tx_resp)
{ {
u8 retries, current_count; u8 retries, current_count;
int scale_rate_index, first_index, last_index; int scale_rate_index, first_index, last_index;
@ -457,14 +456,15 @@ static void rs_tx_status(void *priv_rate,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iwl3945_rs_sta *rs_sta; struct iwl3945_rs_sta *rs_sta;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
retries = tx_resp->retry_count; retries = info->status.retry_count;
first_index = tx_resp->control.tx_rate->hw_value; first_index = sband->bitrates[info->tx_rate_idx].hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
return; return;
@ -525,11 +525,11 @@ static void rs_tx_status(void *priv_rate,
/* Update the last index window with success/failure based on ACK */ /* Update the last index window with success/failure based on ACK */
IWL_DEBUG_RATE("Update rate %d with %s.\n", IWL_DEBUG_RATE("Update rate %d with %s.\n",
last_index, last_index,
(tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? (info->flags & IEEE80211_TX_STAT_ACK) ?
"success" : "failure"); "success" : "failure");
iwl3945_collect_tx_data(rs_sta, iwl3945_collect_tx_data(rs_sta,
&rs_sta->win[last_index], &rs_sta->win[last_index],
tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); info->flags & IEEE80211_TX_STAT_ACK, 1);
/* We updated the rate scale window -- if its been more than /* We updated the rate scale window -- if its been more than
* flush_time since the last run, schedule the flush * flush_time since the last run, schedule the flush
@ -669,7 +669,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
is_multicast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) { !sta || !sta->rate_ctrl_priv) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
sel->rate = rate_lowest(local, sband, sta); sel->rate_idx = rate_lowest_index(local, sband, sta);
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
@ -813,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
IWL_DEBUG_RATE("leave: %d\n", index); IWL_DEBUG_RATE("leave: %d\n", index);
sel->rate = &sband->bitrates[sta->txrate_idx]; sel->rate_idx = sta->txrate_idx;
} }
static struct rate_control_ops rs_ops = { static struct rate_control_ops rs_ops = {

View File

@ -283,8 +283,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv,
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr]; tx_info = &txq->txb[txq->q.read_ptr];
ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0], ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
&tx_info->status);
tx_info->skb[0] = NULL; tx_info->skb[0] = NULL;
iwl3945_hw_txq_free_tfd(priv, txq); iwl3945_hw_txq_free_tfd(priv, txq);
} }
@ -306,7 +305,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
int txq_id = SEQ_TO_QUEUE(sequence); int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence); int index = SEQ_TO_INDEX(sequence);
struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
struct ieee80211_tx_status *tx_status; struct ieee80211_tx_info *info;
struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->status); u32 status = le32_to_cpu(tx_resp->status);
int rate_idx; int rate_idx;
@ -319,19 +318,22 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
return; return;
} }
tx_status = &(txq->txb[txq->q.read_ptr].status); info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
memset(&info->status, 0, sizeof(info->status));
tx_status->retry_count = tx_resp->failure_frame; info->status.retry_count = tx_resp->failure_frame;
/* tx_status->rts_retry_count = tx_resp->failure_rts; */ /* tx_status->rts_retry_count = tx_resp->failure_rts; */
tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
IEEE80211_TX_STATUS_ACK : 0; IEEE80211_TX_STAT_ACK : 0;
IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
txq_id, iwl3945_get_tx_fail_reason(status), status, txq_id, iwl3945_get_tx_fail_reason(status), status,
tx_resp->rate, tx_resp->failure_frame); tx_resp->rate, tx_resp->failure_frame);
rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; if (info->band == IEEE80211_BAND_5GHZ)
rate_idx -= IWL_FIRST_OFDM_RATE;
info->tx_rate_idx = rate_idx;
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
iwl3945_tx_queue_reclaim(priv, txq_id, index); iwl3945_tx_queue_reclaim(priv, txq_id, index);
@ -958,11 +960,12 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
*/ */
void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd, struct iwl3945_cmd *cmd,
struct ieee80211_tx_control *ctrl, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, int sta_id, int tx_id) struct ieee80211_hdr *hdr, int sta_id, int tx_id)
{ {
unsigned long flags; unsigned long flags;
u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
u16 rate_mask; u16 rate_mask;
int rate; int rate;
u8 rts_retry_limit; u8 rts_retry_limit;
@ -974,7 +977,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
tx_flags = cmd->cmd.tx.tx_flags; tx_flags = cmd->cmd.tx.tx_flags;
/* We need to figure out how to get the sta->supp_rates while /* We need to figure out how to get the sta->supp_rates while
* in this running context; perhaps encoding into ctrl->tx_rate? */ * in this running context */
rate_mask = IWL_RATES_MASK; rate_mask = IWL_RATES_MASK;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);

View File

@ -124,7 +124,6 @@ int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i);
/* One for each TFD */ /* One for each TFD */
struct iwl3945_tx_info { struct iwl3945_tx_info {
struct ieee80211_tx_status status;
struct sk_buff *skb[MAX_NUM_OF_TBS]; struct sk_buff *skb[MAX_NUM_OF_TBS];
}; };
@ -645,7 +644,7 @@ extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv); extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv);
extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd, struct iwl3945_cmd *cmd,
struct ieee80211_tx_control *ctrl, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
int sta_id, int tx_id); int sta_id, int tx_id);
extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv); extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv);
@ -836,8 +835,6 @@ struct iwl3945_priv {
u8 mac80211_registered; u8 mac80211_registered;
u32 notif_missed_beacons;
/* Rx'd packet timing information */ /* Rx'd packet timing information */
u32 last_beacon_time; u32 last_beacon_time;
u64 last_tsf; u64 last_tsf;

View File

@ -100,9 +100,14 @@
#include "iwl-commands.h" #include "iwl-commands.h"
#define PCI_LINK_CTRL 0x0F0 /* PCI registers */
#define PCI_LINK_CTRL 0x0F0 /* 1 byte */
#define PCI_POWER_SOURCE 0x0C8 #define PCI_POWER_SOURCE 0x0C8
#define PCI_REG_WUM8 0x0E8 #define PCI_REG_WUM8 0x0E8
/* PCI register values */
#define PCI_LINK_VAL_L0S_EN 0x01
#define PCI_LINK_VAL_L1_EN 0x02
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
#define TFD_QUEUE_SIZE_MAX (256) #define TFD_QUEUE_SIZE_MAX (256)

View File

@ -282,14 +282,20 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
* increment traffic load value for tid and also remove * increment traffic load value for tid and also remove
* any old values if passed the certain time period * any old values if passed the certain time period
*/ */
static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid) static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data,
struct ieee80211_hdr *hdr)
{ {
u32 curr_time = jiffies_to_msecs(jiffies); u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff; u32 time_diff;
s32 index; s32 index;
struct iwl4965_traffic_load *tl = NULL; struct iwl4965_traffic_load *tl = NULL;
u16 fc = le16_to_cpu(hdr->frame_control);
u8 tid;
if (tid >= TID_MAX_LOAD_COUNT) if (ieee80211_is_qos_data(fc)) {
u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
tid = qc[0] & 0xf;
} else
return; return;
tl = &lq_data->load[tid]; tl = &lq_data->load[tid];
@ -481,7 +487,7 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
u32 rate_n_flags = 0; u32 rate_n_flags = 0;
if (is_legacy(tbl->lq_type)) { if (is_legacy(tbl->lq_type)) {
rate_n_flags = iwl4965_rates[index].plcp; rate_n_flags = iwl_rates[index].plcp;
if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
rate_n_flags |= RATE_MCS_CCK_MSK; rate_n_flags |= RATE_MCS_CCK_MSK;
@ -493,11 +499,11 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
rate_n_flags = RATE_MCS_HT_MSK; rate_n_flags = RATE_MCS_HT_MSK;
if (is_siso(tbl->lq_type)) if (is_siso(tbl->lq_type))
rate_n_flags |= iwl4965_rates[index].plcp_siso; rate_n_flags |= iwl_rates[index].plcp_siso;
else if (is_mimo2(tbl->lq_type)) else if (is_mimo2(tbl->lq_type))
rate_n_flags |= iwl4965_rates[index].plcp_mimo2; rate_n_flags |= iwl_rates[index].plcp_mimo2;
else else
rate_n_flags |= iwl4965_rates[index].plcp_mimo3; rate_n_flags |= iwl_rates[index].plcp_mimo3;
} else { } else {
IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type); IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type);
} }
@ -697,7 +703,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
low = index; low = index;
while (low != IWL_RATE_INVALID) { while (low != IWL_RATE_INVALID) {
low = iwl4965_rates[low].prev_rs; low = iwl_rates[low].prev_rs;
if (low == IWL_RATE_INVALID) if (low == IWL_RATE_INVALID)
break; break;
if (rate_mask & (1 << low)) if (rate_mask & (1 << low))
@ -707,7 +713,7 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
high = index; high = index;
while (high != IWL_RATE_INVALID) { while (high != IWL_RATE_INVALID) {
high = iwl4965_rates[high].next_rs; high = iwl_rates[high].next_rs;
if (high == IWL_RATE_INVALID) if (high == IWL_RATE_INVALID)
break; break;
if (rate_mask & (1 << high)) if (rate_mask & (1 << high))
@ -779,8 +785,7 @@ out:
* mac80211 sends us Tx status * mac80211 sends us Tx status
*/ */
static void rs_tx_status(void *priv_rate, struct net_device *dev, static void rs_tx_status(void *priv_rate, struct net_device *dev,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_status *tx_resp)
{ {
int status; int status;
u8 retries; u8 retries;
@ -792,6 +797,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
struct iwl_priv *priv = (struct iwl_priv *)priv_rate; struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = local_to_hw(local); struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl4965_rate_scale_data *window = NULL; struct iwl4965_rate_scale_data *window = NULL;
struct iwl4965_rate_scale_data *search_win = NULL; struct iwl4965_rate_scale_data *search_win = NULL;
u32 tx_rate; u32 tx_rate;
@ -807,11 +813,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
return; return;
/* This packet was aggregated but doesn't carry rate scale info */ /* This packet was aggregated but doesn't carry rate scale info */
if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) && if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
!(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU)) !(info->flags & IEEE80211_TX_STAT_AMPDU))
return; return;
retries = tx_resp->retry_count; retries = info->status.retry_count;
if (retries > 15) if (retries > 15)
retries = 15; retries = 15;
@ -856,20 +862,20 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
if (priv->band == IEEE80211_BAND_5GHZ) if (priv->band == IEEE80211_BAND_5GHZ)
rs_index -= IWL_FIRST_OFDM_RATE; rs_index -= IWL_FIRST_OFDM_RATE;
if ((tx_resp->control.tx_rate == NULL) || if ((info->tx_rate_idx < 0) ||
(tbl_type.is_SGI ^ (tbl_type.is_SGI ^
!!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
(tbl_type.is_fat ^ (tbl_type.is_fat ^
!!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) || !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
(tbl_type.is_dup ^ (tbl_type.is_dup ^
!!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) || !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
(tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) || (tbl_type.ant_type ^ info->antenna_sel_tx) ||
(!!(tx_rate & RATE_MCS_HT_MSK) ^ (!!(tx_rate & RATE_MCS_HT_MSK) ^
!!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) || !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
(!!(tx_rate & RATE_MCS_GF_MSK) ^ (!!(tx_rate & RATE_MCS_GF_MSK) ^
!!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
(hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
tx_resp->control.tx_rate->bitrate)) { hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
goto out; goto out;
} }
@ -923,10 +929,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index); rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
/* Update frame history window with "success" if Tx got ACKed ... */ /* Update frame history window with "success" if Tx got ACKed ... */
if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) status = !!(info->flags & IEEE80211_TX_STAT_ACK);
status = 1;
else
status = 0;
/* If type matches "search" table, /* If type matches "search" table,
* add final tx status to "search" history */ * add final tx status to "search" history */
@ -937,10 +940,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
tpt = search_tbl->expected_tpt[rs_index]; tpt = search_tbl->expected_tpt[rs_index];
else else
tpt = 0; tpt = 0;
if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) if (info->flags & IEEE80211_TX_CTL_AMPDU)
rs_collect_tx_data(search_win, rs_index, tpt, rs_collect_tx_data(search_win, rs_index, tpt,
tx_resp->ampdu_ack_len, info->status.ampdu_ack_len,
tx_resp->ampdu_ack_map); info->status.ampdu_ack_map);
else else
rs_collect_tx_data(search_win, rs_index, tpt, rs_collect_tx_data(search_win, rs_index, tpt,
1, status); 1, status);
@ -953,10 +956,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
tpt = curr_tbl->expected_tpt[rs_index]; tpt = curr_tbl->expected_tpt[rs_index];
else else
tpt = 0; tpt = 0;
if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) if (info->flags & IEEE80211_TX_CTL_AMPDU)
rs_collect_tx_data(window, rs_index, tpt, rs_collect_tx_data(window, rs_index, tpt,
tx_resp->ampdu_ack_len, info->status.ampdu_ack_len,
tx_resp->ampdu_ack_map); info->status.ampdu_ack_map);
else else
rs_collect_tx_data(window, rs_index, tpt, rs_collect_tx_data(window, rs_index, tpt,
1, status); 1, status);
@ -965,10 +968,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
/* If not searching for new mode, increment success/failed counter /* If not searching for new mode, increment success/failed counter
* ... these help determine when to start searching again */ * ... these help determine when to start searching again */
if (lq_sta->stay_in_tbl) { if (lq_sta->stay_in_tbl) {
if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) { if (info->flags & IEEE80211_TX_CTL_AMPDU) {
lq_sta->total_success += tx_resp->ampdu_ack_map; lq_sta->total_success += info->status.ampdu_ack_map;
lq_sta->total_failed += lq_sta->total_failed +=
(tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map); (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
} else { } else {
if (status) if (status)
lq_sta->total_success++; lq_sta->total_success++;
@ -1333,7 +1336,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
lq_sta->search_better_tbl = 1; lq_sta->search_better_tbl = 1;
goto out; goto out;
} }
break;
case IWL_LEGACY_SWITCH_SISO: case IWL_LEGACY_SWITCH_SISO:
IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n"); IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n");
@ -1419,9 +1422,9 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
lq_sta->search_better_tbl = 1; lq_sta->search_better_tbl = 1;
goto out; goto out;
} }
break;
case IWL_SISO_SWITCH_MIMO2: case IWL_SISO_SWITCH_MIMO2:
IWL_DEBUG_RATE("LQ: SISO switch to MIMO\n"); IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n");
memcpy(search_tbl, tbl, sz); memcpy(search_tbl, tbl, sz);
search_tbl->is_SGI = 0; search_tbl->is_SGI = 0;
search_tbl->ant_type = ANT_AB; /*FIXME:RS*/ search_tbl->ant_type = ANT_AB; /*FIXME:RS*/
@ -1433,6 +1436,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
} }
break; break;
case IWL_SISO_SWITCH_GI: case IWL_SISO_SWITCH_GI:
if (!tbl->is_fat &&
!(priv->current_ht_config.sgf &
HT_SHORT_GI_20MHZ))
break;
if (tbl->is_fat &&
!(priv->current_ht_config.sgf &
HT_SHORT_GI_40MHZ))
break;
IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n"); IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n");
memcpy(search_tbl, tbl, sz); memcpy(search_tbl, tbl, sz);
@ -1515,6 +1527,15 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
break; break;
case IWL_MIMO_SWITCH_GI: case IWL_MIMO_SWITCH_GI:
if (!tbl->is_fat &&
!(priv->current_ht_config.sgf &
HT_SHORT_GI_20MHZ))
break;
if (tbl->is_fat &&
!(priv->current_ht_config.sgf &
HT_SHORT_GI_40MHZ))
break;
IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n"); IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n");
/* Set up new search table for MIMO */ /* Set up new search table for MIMO */
@ -1668,9 +1689,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
u8 active_tbl = 0; u8 active_tbl = 0;
u8 done_search = 0; u8 done_search = 0;
u16 high_low; u16 high_low;
s32 sr;
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
u8 tid = MAX_TID_COUNT; u8 tid = MAX_TID_COUNT;
__le16 *qc;
#endif #endif
IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
@ -1693,11 +1714,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
qc = ieee80211_get_qos_ctrl(hdr); rs_tl_add_packet(lq_sta, hdr);
if (qc) {
tid = (u8)(le16_to_cpu(*qc) & 0xf);
rs_tl_add_packet(lq_sta, tid);
}
#endif #endif
/* /*
* Select rate-scale / modulation-mode table to work with in * Select rate-scale / modulation-mode table to work with in
@ -1848,6 +1865,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
low = high_low & 0xff; low = high_low & 0xff;
high = (high_low >> 8) & 0xff; high = (high_low >> 8) & 0xff;
sr = window->success_ratio;
/* Collect measured throughputs for current and adjacent rates */ /* Collect measured throughputs for current and adjacent rates */
current_tpt = window->average_tpt; current_tpt = window->average_tpt;
if (low != IWL_RATE_INVALID) if (low != IWL_RATE_INVALID)
@ -1855,19 +1874,22 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (high != IWL_RATE_INVALID) if (high != IWL_RATE_INVALID)
high_tpt = tbl->win[high].average_tpt; high_tpt = tbl->win[high].average_tpt;
/* Assume rate increase */ scale_action = 0;
scale_action = 1;
/* Too many failures, decrease rate */ /* Too many failures, decrease rate */
if ((window->success_ratio <= IWL_RATE_DECREASE_TH) || if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
(current_tpt == 0)) {
IWL_DEBUG_RATE("decrease rate because of low success_ratio\n"); IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
scale_action = -1; scale_action = -1;
/* No throughput measured yet for adjacent rates; try increase. */ /* No throughput measured yet for adjacent rates; try increase. */
} else if ((low_tpt == IWL_INVALID_VALUE) && } else if ((low_tpt == IWL_INVALID_VALUE) &&
(high_tpt == IWL_INVALID_VALUE)) (high_tpt == IWL_INVALID_VALUE)) {
scale_action = 1;
if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
scale_action = 1;
else if (low != IWL_RATE_INVALID)
scale_action = -1;
}
/* Both adjacent throughputs are measured, but neither one has better /* Both adjacent throughputs are measured, but neither one has better
* throughput; we're using the best rate, don't change it! */ * throughput; we're using the best rate, don't change it! */
@ -1883,9 +1905,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
/* Higher adjacent rate's throughput is measured */ /* Higher adjacent rate's throughput is measured */
if (high_tpt != IWL_INVALID_VALUE) { if (high_tpt != IWL_INVALID_VALUE) {
/* Higher rate has better throughput */ /* Higher rate has better throughput */
if (high_tpt > current_tpt) if (high_tpt > current_tpt &&
sr >= IWL_RATE_INCREASE_TH) {
scale_action = 1; scale_action = 1;
else { } else {
IWL_DEBUG_RATE IWL_DEBUG_RATE
("decrease rate because of high tpt\n"); ("decrease rate because of high tpt\n");
scale_action = -1; scale_action = -1;
@ -1898,23 +1921,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
IWL_DEBUG_RATE IWL_DEBUG_RATE
("decrease rate because of low tpt\n"); ("decrease rate because of low tpt\n");
scale_action = -1; scale_action = -1;
} else } else if (sr >= IWL_RATE_INCREASE_TH) {
scale_action = 1; scale_action = 1;
}
} }
} }
/* Sanity check; asked for decrease, but success rate or throughput /* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate. Don't change it. */ * has been good at old rate. Don't change it. */
if (scale_action == -1) { if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
if ((low != IWL_RATE_INVALID) && ((sr > IWL_RATE_HIGH_TH) ||
((window->success_ratio > IWL_RATE_HIGH_TH) ||
(current_tpt > (100 * tbl->expected_tpt[low])))) (current_tpt > (100 * tbl->expected_tpt[low]))))
scale_action = 0;
/* Sanity check; asked for increase, but success rate has not been great
* even at old rate, higher rate will be worse. Don't change it. */
} else if ((scale_action == 1) &&
(window->success_ratio < IWL_RATE_INCREASE_TH))
scale_action = 0; scale_action = 0;
switch (scale_action) { switch (scale_action) {
@ -1943,7 +1960,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
"high %d type %d\n", "high %d type %d\n",
index, scale_action, low, high, tbl->lq_type); index, scale_action, low, high, tbl->lq_type);
lq_update: lq_update:
/* Replace uCode's rate table for the destination station. */ /* Replace uCode's rate table for the destination station. */
if (update_lq) { if (update_lq) {
rate = rate_n_flags_from_tbl(tbl, index, is_green); rate = rate_n_flags_from_tbl(tbl, index, is_green);
@ -2088,7 +2105,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
i = 0; i = 0;
/* FIXME:RS: This is also wrong in 4965 */ /* FIXME:RS: This is also wrong in 4965 */
rate = iwl4965_rates[i].plcp; rate = iwl_rates[i].plcp;
rate |= RATE_MCS_ANT_B_MSK; rate |= RATE_MCS_ANT_B_MSK;
rate &= ~RATE_MCS_ANT_A_MSK; rate &= ~RATE_MCS_ANT_A_MSK;
@ -2135,7 +2152,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
fc = le16_to_cpu(hdr->frame_control); fc = le16_to_cpu(hdr->frame_control);
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) { !sta || !sta->rate_ctrl_priv) {
sel->rate = rate_lowest(local, sband, sta); sel->rate_idx = rate_lowest_index(local, sband, sta);
goto out; goto out;
} }
@ -2150,7 +2167,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
if (sta_id == IWL_INVALID_STATION) { if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n", IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, hdr->addr1)); print_mac(mac, hdr->addr1));
sta_id = iwl4965_add_station_flags(priv, hdr->addr1, sta_id = iwl_add_station_flags(priv, hdr->addr1,
0, CMD_ASYNC, NULL); 0, CMD_ASYNC, NULL);
} }
if ((sta_id != IWL_INVALID_STATION)) { if ((sta_id != IWL_INVALID_STATION)) {
@ -2165,11 +2182,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
done: done:
if ((i < 0) || (i > IWL_RATE_COUNT)) { if ((i < 0) || (i > IWL_RATE_COUNT)) {
sel->rate = rate_lowest(local, sband, sta); sel->rate_idx = rate_lowest_index(local, sband, sta);
goto out; goto out;
} }
sel->rate = &priv->ieee_rates[i]; if (sband->band == IEEE80211_BAND_5GHZ)
i -= IWL_FIRST_OFDM_RATE;
sel->rate_idx = i;
out: out:
rcu_read_unlock(); rcu_read_unlock();
} }
@ -2234,7 +2253,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
if (sta_id == IWL_INVALID_STATION) { if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n", IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
sta_id = iwl4965_add_station_flags(priv, sta->addr, sta_id = iwl_add_station_flags(priv, sta->addr,
0, CMD_ASYNC, NULL); 0, CMD_ASYNC, NULL);
} }
if ((sta_id != IWL_INVALID_STATION)) { if ((sta_id != IWL_INVALID_STATION)) {
@ -2425,6 +2444,7 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv,
repeat_rate--; repeat_rate--;
} }
lq_cmd->agg_params.agg_frame_cnt_limit = 64;
lq_cmd->agg_params.agg_dis_start_th = 3; lq_cmd->agg_params.agg_dis_start_th = 3;
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000); lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
} }
@ -2691,7 +2711,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
int active = lq_sta->active_tbl; int active = lq_sta->active_tbl;
cnt += cnt +=
sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2); sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2);
mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
@ -2702,7 +2722,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
samples += lq_sta->lq_info[active].win[i].counter; samples += lq_sta->lq_info[active].win[i].counter;
good += lq_sta->lq_info[active].win[i].success_counter; good += lq_sta->lq_info[active].win[i].success_counter;
success += lq_sta->lq_info[active].win[i].success_counter * success += lq_sta->lq_info[active].win[i].success_counter *
iwl4965_rates[i].ieee; iwl_rates[i].ieee;
if (lq_sta->lq_info[active].win[i].stamp) { if (lq_sta->lq_info[active].win[i].stamp) {
int delta = int delta =
@ -2722,10 +2742,11 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
i = j; i = j;
} }
/* Display the average rate of all samples taken. /*
* * Display the average rate of all samples taken.
* NOTE: We multiply # of samples by 2 since the IEEE measurement * NOTE: We multiply # of samples by 2 since the IEEE measurement
* added from iwl4965_rates is actually 2X the rate */ * added from iwl_rates is actually 2X the rate.
*/
if (samples) if (samples)
cnt += sprintf(&buf[cnt], cnt += sprintf(&buf[cnt],
"\nAverage rate is %3d.%02dMbs over last %4dms\n" "\nAverage rate is %3d.%02dMbs over last %4dms\n"

View File

@ -29,7 +29,7 @@
#include "iwl-dev.h" #include "iwl-dev.h"
struct iwl4965_rate_info { struct iwl_rate_info {
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
@ -45,7 +45,7 @@ struct iwl4965_rate_info {
/* /*
* These serve as indexes into * These serve as indexes into
* struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
*/ */
enum { enum {
IWL_RATE_1M_INDEX = 0, IWL_RATE_1M_INDEX = 0,
@ -240,7 +240,7 @@ enum {
#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING) #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y)) #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
enum iwl_table_type { enum iwl_table_type {
LQ_NONE, LQ_NONE,
@ -279,7 +279,7 @@ static inline u8 num_of_ant(u8 mask)
static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
{ {
u8 rate = iwl4965_rates[rate_index].prev_ieee; u8 rate = iwl_rates[rate_index].prev_ieee;
if (rate == IWL_RATE_INVALID) if (rate == IWL_RATE_INVALID)
rate = rate_index; rate = rate_index;

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,41 @@
#define IWL5000_UCODE_API "-1" #define IWL5000_UCODE_API "-1"
static const u16 iwl5000_default_queue_to_tx_fifo[] = {
IWL_TX_FIFO_AC3,
IWL_TX_FIFO_AC2,
IWL_TX_FIFO_AC1,
IWL_TX_FIFO_AC0,
IWL50_CMD_FIFO_NUM,
IWL_TX_FIFO_HCCA_1,
IWL_TX_FIFO_HCCA_2
};
/* FIXME: same implementation as 4965 */
static int iwl5000_apm_stop_master(struct iwl_priv *priv)
{
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
/* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
ret = iwl_poll_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
if (ret < 0)
goto out;
out:
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n");
return ret;
}
static int iwl5000_apm_init(struct iwl_priv *priv) static int iwl5000_apm_init(struct iwl_priv *priv)
{ {
int ret = 0; int ret = 0;
@ -53,6 +88,10 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
/* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
/* set "initialization complete" bit to move adapter /* set "initialization complete" bit to move adapter
@ -73,19 +112,91 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
return ret; return ret;
/* enable DMA */ /* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20); udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS); APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
return ret; return ret;
} }
/* FIXME: this is indentical to 4965 */
static void iwl5000_apm_stop(struct iwl_priv *priv)
{
unsigned long flags;
iwl5000_apm_stop_master(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
spin_unlock_irqrestore(&priv->lock, flags);
}
static int iwl5000_apm_reset(struct iwl_priv *priv)
{
int ret = 0;
unsigned long flags;
iwl5000_apm_stop_master(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
/* FIXME: put here L1A -L0S w/a */
iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
/* set "initialization complete" bit to move adapter
* D0U* --> D0A* state */
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock stabilization */
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
if (ret < 0) {
IWL_DEBUG_INFO("Failed to init the card\n");
goto out;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto out;
/* enable DMA */
iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
static void iwl5000_nic_config(struct iwl_priv *priv) static void iwl5000_nic_config(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
@ -96,8 +207,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link); pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
/* disable L1 entry -- workaround for pre-B1 */ /* L1 is enabled by BIOS */
pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02); if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
/* diable L0S disabled L1A enabled */
iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
else
/* L0S enabled L1A disabled */
iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
@ -279,6 +395,8 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */ #endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset) size_t offset)
{ {
@ -287,6 +405,423 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
return &priv->eeprom[address]; return &priv->eeprom[address];
} }
/*
* Calibration
*/
static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
{
u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
struct iwl5000_calibration cal_cmd = {
.op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
.data = {
(u8)xtal_calib[0],
(u8)xtal_calib[1],
}
};
return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
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;
struct iwl_host_cmd cmd = {
.id = CALIBRATION_CFG_CMD,
.len = sizeof(struct iwl5000_calib_cfg_cmd),
.data = &calib_cfg_cmd,
};
memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
return iwl_send_cmd(priv, &cmd);
}
static void iwl5000_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
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);
/* reduce the size of the length field itself */
len -= 4;
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);
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);
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);
break;
default:
IWL_ERROR("Unknown calibration notification %d\n",
hdr->op_code);
return;
}
}
static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n");
queue_work(priv->workqueue, &priv->restart);
}
/*
* ucode
*/
static int iwl5000_load_section(struct iwl_priv *priv,
struct fw_desc *image,
u32 dst_addr)
{
int ret = 0;
unsigned long flags;
dma_addr_t phy_addr = image->p_addr;
u32 byte_cnt = image->len;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
iwl_write_direct32(priv,
FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
iwl_write_direct32(priv,
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
/* FIME: write the MSB of the phy_addr in CTRL1
* iwl_write_direct32(priv,
IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL),
((phy_addr & MSB_MSK)
<< FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count);
*/
iwl_write_direct32(priv,
FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt);
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int iwl5000_load_given_ucode(struct iwl_priv *priv,
struct fw_desc *inst_image,
struct fw_desc *data_image)
{
int ret = 0;
ret = iwl5000_load_section(
priv, inst_image, RTC_INST_LOWER_BOUND);
if (ret)
return ret;
IWL_DEBUG_INFO("INST uCode section being loaded...\n");
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
priv->ucode_write_complete, 5 * HZ);
if (ret == -ERESTARTSYS) {
IWL_ERROR("Could not load the INST uCode section due "
"to interrupt\n");
return ret;
}
if (!ret) {
IWL_ERROR("Could not load the INST uCode section\n");
return -ETIMEDOUT;
}
priv->ucode_write_complete = 0;
ret = iwl5000_load_section(
priv, data_image, RTC_DATA_LOWER_BOUND);
if (ret)
return ret;
IWL_DEBUG_INFO("DATA uCode section being loaded...\n");
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
priv->ucode_write_complete, 5 * HZ);
if (ret == -ERESTARTSYS) {
IWL_ERROR("Could not load the INST uCode section due "
"to interrupt\n");
return ret;
} else if (!ret) {
IWL_ERROR("Could not load the DATA uCode section\n");
return -ETIMEDOUT;
} else
ret = 0;
priv->ucode_write_complete = 0;
return ret;
}
static int iwl5000_load_ucode(struct iwl_priv *priv)
{
int ret = 0;
/* check whether init ucode should be loaded, or rather runtime ucode */
if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n");
ret = iwl5000_load_given_ucode(priv,
&priv->ucode_init, &priv->ucode_init_data);
if (!ret) {
IWL_DEBUG_INFO("Init ucode load complete.\n");
priv->ucode_type = UCODE_INIT;
}
} else {
IWL_DEBUG_INFO("Init ucode not found, or already loaded. "
"Loading runtime ucode...\n");
ret = iwl5000_load_given_ucode(priv,
&priv->ucode_code, &priv->ucode_data);
if (!ret) {
IWL_DEBUG_INFO("Runtime ucode load complete.\n");
priv->ucode_type = UCODE_RT;
}
}
return ret;
}
static void iwl5000_init_alive_start(struct iwl_priv *priv)
{
int ret = 0;
/* Check alive response for "valid" sign from uCode */
if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
/* We had an error bringing up the hardware, so take it
* all the way back down so we can try again */
IWL_DEBUG_INFO("Initialize Alive failed.\n");
goto restart;
}
/* initialize uCode was loaded... verify inst image.
* This is a paranoid check, because we would not have gotten the
* "initialize" alive if code weren't properly loaded. */
if (iwl_verify_ucode(priv)) {
/* Runtime instruction load was bad;
* take it all the way back down so we can try again */
IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
goto restart;
}
iwlcore_clear_stations_table(priv);
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
IWL_WARNING("Could not complete ALIVE transition: %d\n", ret);
goto restart;
}
iwl5000_send_calib_cfg(priv);
return;
restart:
/* real restart (first load init_ucode) */
queue_work(priv->workqueue, &priv->restart);
}
static void iwl5000_set_wr_ptrs(struct iwl_priv *priv,
int txq_id, u32 index)
{
iwl_write_direct32(priv, HBUS_TARG_WRPTR,
(index & 0xff) | (txq_id << 8));
iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
}
static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
int tx_fifo_id, int scd_retry)
{
int txq_id = txq->q.id;
int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
(active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
(tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
(1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
IWL50_SCD_QUEUE_STTS_REG_MSK);
txq->sched_retry = scd_retry;
IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
active ? "Activate" : "Deactivate",
scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
}
static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
{
struct iwl_wimax_coex_cmd coex_cmd;
memset(&coex_cmd, 0, sizeof(coex_cmd));
return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
sizeof(coex_cmd), &coex_cmd);
}
static int iwl5000_alive_notify(struct iwl_priv *priv)
{
u32 a;
int i = 0;
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
a += 4)
iwl_write_targ_mem(priv, a, 0);
for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
a += 4)
iwl_write_targ_mem(priv, a, 0);
for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
iwl_write_targ_mem(priv, a, 0);
iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
(priv->shared_phys +
offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10);
iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
IWL50_SCD_QUEUECHAIN_SEL_ALL(
priv->hw_params.max_txq_num));
iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
/* initiate the queues */
for (i = 0; i < priv->hw_params.max_txq_num; i++) {
iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
iwl_write_targ_mem(priv, priv->scd_base_addr +
IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
iwl_write_targ_mem(priv, priv->scd_base_addr +
IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
sizeof(u32),
((SCD_WIN_SIZE <<
IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
((SCD_FRAME_LIMIT <<
IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
}
iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
IWL_MASK(0, priv->hw_params.max_txq_num));
/* Activate all Tx DMA/FIFO channels */
priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
/* map qos queues to fifos one-to-one */
for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
int ac = iwl5000_default_queue_to_tx_fifo[i];
iwl_txq_ctx_activate(priv, i);
iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
}
/* TODO - need to initialize those FIFOs inside the loop above,
* not only mark them as active */
iwl_txq_ctx_activate(priv, 4);
iwl_txq_ctx_activate(priv, 7);
iwl_txq_ctx_activate(priv, 8);
iwl_txq_ctx_activate(priv, 9);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
iwl5000_send_wimax_coex(priv);
iwl5000_send_Xtal_calib(priv);
if (priv->ucode_type == UCODE_RT) {
iwl5000_send_calib_results(priv);
set_bit(STATUS_READY, &priv->status);
priv->is_open = 1;
}
return 0;
}
static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
{ {
if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) || if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
@ -298,7 +833,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto; priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K) if (priv->cfg->mod_params->amsdu_size_8K)
@ -430,6 +964,26 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
} }
} }
static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
int txq_id = txq->q.id;
struct iwl5000_shared *shared_data = priv->shared_virt;
u8 sta = 0;
if (txq_id != IWL_CMD_QUEUE_NUM)
sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id;
shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
val = cpu_to_le16(1 | (sta << 12));
if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
shared_data->queues_byte_cnt_tbls[txq_id].
tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr].
val = cpu_to_le16(1 | (sta << 12));
}
}
static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
{ {
u16 size = (u16)sizeof(struct iwl_addsta_cmd); u16 size = (u16)sizeof(struct iwl_addsta_cmd);
@ -438,31 +992,326 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
} }
static int iwl5000_disable_tx_fifo(struct iwl_priv *priv) /*
* Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
* must be called under priv->lock and mac access
*/
static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
{ {
unsigned long flags; iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
int ret; }
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv); static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
if (unlikely(ret)) { {
IWL_ERROR("Tx fifo reset failed"); __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
spin_unlock_irqrestore(&priv->lock, flags); tx_resp->frame_count);
return ret; return le32_to_cpu(*scd_ssn) & MAX_SN;
}
static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
struct iwl_ht_agg *agg,
struct iwl5000_tx_resp *tx_resp,
u16 start_idx)
{
u16 status;
struct agg_tx_status *frame_status = &tx_resp->status;
struct ieee80211_tx_info *info = NULL;
struct ieee80211_hdr *hdr = NULL;
int i, sh;
int txq_id, idx;
u16 seq;
if (agg->wait_for_ba)
IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
agg->frame_count = tx_resp->frame_count;
agg->start_idx = start_idx;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
agg->bitmap = 0;
/* # frames attempted by Tx command */
if (agg->frame_count == 1) {
/* Only one frame was attempted; no block-ack will arrive */
status = le16_to_cpu(frame_status[0].status);
seq = le16_to_cpu(frame_status[0].sequence);
idx = SEQ_TO_INDEX(seq);
txq_id = SEQ_TO_QUEUE(seq);
/* FIXME: code repetition */
IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
info->status.retry_count = tx_resp->failure_frame;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->flags |= iwl_is_tx_success(status)?
IEEE80211_TX_STAT_ACK : 0;
iwl4965_hwrate_to_tx_control(priv,
le32_to_cpu(tx_resp->rate_n_flags),
info);
/* FIXME: code repetition end */
IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
status & 0xff, tx_resp->failure_frame);
IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
agg->wait_for_ba = 0;
} else {
/* Two or more frames were attempted; expect block-ack */
u64 bitmap = 0;
int start = agg->start_idx;
/* Construct bit-map of pending frames within Tx window */
for (i = 0; i < agg->frame_count; i++) {
u16 sc;
status = le16_to_cpu(frame_status[i].status);
seq = le16_to_cpu(frame_status[i].sequence);
idx = SEQ_TO_INDEX(seq);
txq_id = SEQ_TO_QUEUE(seq);
if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
AGG_TX_STATE_ABORT_MSK))
continue;
IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
agg->frame_count, txq_id, idx);
hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
sc = le16_to_cpu(hdr->seq_ctrl);
if (idx != (SEQ_TO_SN(sc) & 0xff)) {
IWL_ERROR("BUG_ON idx doesn't match seq control"
" idx=%d, seq_idx=%d, seq=%d\n",
idx, SEQ_TO_SN(sc),
hdr->seq_ctrl);
return -1;
}
IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
i, idx, SEQ_TO_SN(sc));
sh = idx - start;
if (sh > 64) {
sh = (start - idx) + 0xff;
bitmap = bitmap << sh;
sh = 0;
start = idx;
} else if (sh < -64)
sh = 0xff - (start - idx);
else if (sh < 0) {
sh = start - idx;
start = idx;
bitmap = bitmap << sh;
sh = 0;
}
bitmap |= (1 << sh);
IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
start, (u32)(bitmap & 0xFFFFFFFF));
}
agg->bitmap = bitmap;
agg->start_idx = start;
agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
agg->frame_count, agg->start_idx,
(unsigned long long)agg->bitmap);
if (bitmap)
agg->wait_for_ba = 1;
} }
iwl_write_prph(priv, IWL50_SCD_TXFACT, 0);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0; return 0;
} }
static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct ieee80211_tx_info *info;
struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le16_to_cpu(tx_resp->status.status);
#ifdef CONFIG_IWL4965_HT
int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
u16 fc;
struct ieee80211_hdr *hdr;
u8 *qc = NULL;
#endif
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
"is out of range [0-%d] %d %d\n", txq_id,
index, txq->q.n_bd, txq->q.write_ptr,
txq->q.read_ptr);
return;
}
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
memset(&info->status, 0, sizeof(info->status));
#ifdef CONFIG_IWL4965_HT
hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
fc = le16_to_cpu(hdr->frame_control);
if (ieee80211_is_qos_data(fc)) {
qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
tid = qc[0] & 0xf;
}
sta_id = iwl_get_ra_sta_id(priv, hdr);
if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
IWL_ERROR("Station not known\n");
return;
}
if (txq->sched_retry) {
const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
if (!qc)
return;
agg = &priv->stations[sta_id].tid[tid].agg;
iwl5000_tx_status_reply_tx(priv, agg, tx_resp, index);
if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
/* TODO: send BAR */
}
if (txq->q.read_ptr != (scd_ssn & 0xff)) {
int freed, ampdu_q;
index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
txq_id >= 0 && priv->mac80211_registered &&
agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
/* calculate mac80211 ampdu sw queue to wake */
ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
priv->hw->queues;
if (agg->state == IWL_AGG_OFF)
ieee80211_wake_queue(priv->hw, txq_id);
else
ieee80211_wake_queue(priv->hw, ampdu_q);
}
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
}
} else {
#endif /* CONFIG_IWL4965_HT */
info->status.retry_count = tx_resp->failure_frame;
info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
info);
IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
"retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
status, le32_to_cpu(tx_resp->rate_n_flags),
tx_resp->failure_frame);
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
#ifdef CONFIG_IWL4965_HT
if (index != -1) {
int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
if (tid != MAX_TID_COUNT)
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
(txq_id >= 0) && priv->mac80211_registered)
ieee80211_wake_queue(priv->hw, txq_id);
if (tid != MAX_TID_COUNT)
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
}
}
#endif /* CONFIG_IWL4965_HT */
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
}
/* Currently 5000 is the supperset of everything */
static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
{
return len;
}
static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
{
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
iwl5000_rx_calib_result;
priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
iwl5000_rx_calib_complete;
priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx;
}
static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= RTC_DATA_LOWER_BOUND) &&
(addr < IWL50_RTC_DATA_UPPER_BOUND);
}
static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
{
int ret = 0;
struct iwl5000_rxon_assoc_cmd rxon_assoc;
const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
if ((rxon1->flags == rxon2->flags) &&
(rxon1->filter_flags == rxon2->filter_flags) &&
(rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
(rxon1->ofdm_ht_single_stream_basic_rates ==
rxon2->ofdm_ht_single_stream_basic_rates) &&
(rxon1->ofdm_ht_dual_stream_basic_rates ==
rxon2->ofdm_ht_dual_stream_basic_rates) &&
(rxon1->ofdm_ht_triple_stream_basic_rates ==
rxon2->ofdm_ht_triple_stream_basic_rates) &&
(rxon1->acquisition_data == rxon2->acquisition_data) &&
(rxon1->rx_chain == rxon2->rx_chain) &&
(rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
return 0;
}
rxon_assoc.flags = priv->staging_rxon.flags;
rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
rxon_assoc.reserved1 = 0;
rxon_assoc.reserved2 = 0;
rxon_assoc.reserved3 = 0;
rxon_assoc.ofdm_ht_single_stream_basic_rates =
priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
rxon_assoc.ofdm_ht_dual_stream_basic_rates =
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
rxon_assoc.ofdm_ht_triple_stream_basic_rates =
priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
sizeof(rxon_assoc), &rxon_assoc, NULL);
if (ret)
return ret;
return ret;
}
static struct iwl_hcmd_ops iwl5000_hcmd = { static struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
}; };
static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.get_hcmd_size = iwl5000_get_hcmd_size,
.build_addsta_hcmd = iwl5000_build_addsta_hcmd, .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB #ifdef CONFIG_IWL5000_RUN_TIME_CALIB
.gain_computation = iwl5000_gain_computation, .gain_computation = iwl5000_gain_computation,
@ -476,9 +1325,17 @@ static struct iwl_lib_ops iwl5000_lib = {
.free_shared_mem = iwl5000_free_shared_mem, .free_shared_mem = iwl5000_free_shared_mem,
.shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.disable_tx_fifo = iwl5000_disable_tx_fifo, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwl5000_txq_set_sched,
.rx_handler_setup = iwl5000_rx_handler_setup,
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
.stop = iwl5000_apm_stop,
.config = iwl5000_nic_config, .config = iwl5000_nic_config,
.set_pwr_src = iwl4965_set_pwr_src, .set_pwr_src = iwl4965_set_pwr_src,
}, },

View File

@ -426,6 +426,9 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
struct iwl_sensitivity_data *data = NULL; struct iwl_sensitivity_data *data = NULL;
const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
if (priv->disable_sens_cal)
return;
IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n"); IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n");
/* Clear driver's sensitivity algo data */ /* Clear driver's sensitivity algo data */
@ -486,6 +489,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
unsigned long flags; unsigned long flags;
struct statistics_general_data statis; struct statistics_general_data statis;
if (priv->disable_sens_cal)
return;
data = &(priv->sensitivity_data); data = &(priv->sensitivity_data);
if (!iwl_is_associated(priv)) { if (!iwl_is_associated(priv)) {
@ -608,6 +614,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
unsigned long flags; unsigned long flags;
struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general); struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
if (priv->disable_chain_noise_cal)
return;
data = &(priv->chain_noise_data); data = &(priv->chain_noise_data);
/* Accumulate just the first 20 beacons after the first association, /* Accumulate just the first 20 beacons after the first association,
@ -777,3 +786,21 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
} }
EXPORT_SYMBOL(iwl_chain_noise_calibration); EXPORT_SYMBOL(iwl_chain_noise_calibration);
void iwl_reset_run_time_calib(struct iwl_priv *priv)
{
int i;
memset(&(priv->sensitivity_data), 0,
sizeof(struct iwl_sensitivity_data));
memset(&(priv->chain_noise_data), 0,
sizeof(struct iwl_chain_noise_data));
for (i = 0; i < NUM_RX_CHAINS; i++)
priv->chain_noise_data.delta_gain_code[i] =
CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
/* Ask for statistics now, the uCode will send notification
* periodically after association */
iwl_send_statistics_request(priv, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_reset_run_time_calib);

View File

@ -78,10 +78,12 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
struct iwl4965_notif_statistics *resp); struct iwl4965_notif_statistics *resp);
void iwl_init_sensitivity(struct iwl_priv *priv); void iwl_init_sensitivity(struct iwl_priv *priv);
void iwl_reset_run_time_calib(struct iwl_priv *priv);
static inline void iwl_chain_noise_reset(struct iwl_priv *priv) static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
{ {
if (priv->cfg->ops->utils->chain_noise_reset)
if (!priv->disable_chain_noise_cal &&
priv->cfg->ops->utils->chain_noise_reset)
priv->cfg->ops->utils->chain_noise_reset(priv); priv->cfg->ops->utils->chain_noise_reset(priv);
} }
#else #else
@ -99,6 +101,9 @@ static inline void iwl_init_sensitivity(struct iwl_priv *priv)
static inline void iwl_chain_noise_reset(struct iwl_priv *priv) static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
{ {
} }
static inline void iwl_reset_run_time_calib(struct iwl_priv *priv)
{
}
#endif #endif
#endif /* __iwl_calib_h__ */ #endif /* __iwl_calib_h__ */

View File

@ -93,6 +93,11 @@ enum {
REPLY_LEDS_CMD = 0x48, REPLY_LEDS_CMD = 0x48,
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
/* WiMAX coexistence */
COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */
COEX_MEDIUM_NOTIFICATION = 0x5b,
COEX_EVENT_CMD = 0x5c,
/* 802.11h related */ /* 802.11h related */
RADAR_NOTIFICATION = 0x70, /* not used */ RADAR_NOTIFICATION = 0x70, /* not used */
REPLY_QUIET_CMD = 0x71, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */
@ -368,7 +373,7 @@ struct iwl4965_tx_power_db {
* 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
* for each of 5 frequency ranges. * for each of 5 frequency ranges.
*/ */
struct iwl4965_init_alive_resp { struct iwl_init_alive_resp {
u8 ucode_minor; u8 ucode_minor;
u8 ucode_major; u8 ucode_major;
__le16 reserved1; __le16 reserved1;
@ -444,7 +449,7 @@ struct iwl4965_init_alive_resp {
* The Linux driver can print both logs to the system log when a uCode error * The Linux driver can print both logs to the system log when a uCode error
* occurs. * occurs.
*/ */
struct iwl4965_alive_resp { struct iwl_alive_resp {
u8 ucode_minor; u8 ucode_minor;
u8 ucode_major; u8 ucode_major;
__le16 reserved1; __le16 reserved1;
@ -468,7 +473,7 @@ union tsf {
/* /*
* REPLY_ERROR = 0x2 (response only, not a command) * REPLY_ERROR = 0x2 (response only, not a command)
*/ */
struct iwl4965_error_resp { struct iwl_error_resp {
__le32 error_type; __le32 error_type;
u8 cmd_id; u8 cmd_id;
u8 reserved1; u8 reserved1;
@ -600,6 +605,46 @@ struct iwl4965_rxon_cmd {
u8 ofdm_ht_dual_stream_basic_rates; u8 ofdm_ht_dual_stream_basic_rates;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* 5000 HW just extend this cmmand */
struct iwl_rxon_cmd {
u8 node_addr[6];
__le16 reserved1;
u8 bssid_addr[6];
__le16 reserved2;
u8 wlap_bssid_addr[6];
__le16 reserved3;
u8 dev_type;
u8 air_propagation;
__le16 rx_chain;
u8 ofdm_basic_rates;
u8 cck_basic_rates;
__le16 assoc_id;
__le32 flags;
__le32 filter_flags;
__le16 channel;
u8 ofdm_ht_single_stream_basic_rates;
u8 ofdm_ht_dual_stream_basic_rates;
u8 ofdm_ht_triple_stream_basic_rates;
u8 reserved5;
__le16 acquisition_data;
__le16 reserved6;
} __attribute__ ((packed));
struct iwl5000_rxon_assoc_cmd {
__le32 flags;
__le32 filter_flags;
u8 ofdm_basic_rates;
u8 cck_basic_rates;
__le16 reserved1;
u8 ofdm_ht_single_stream_basic_rates;
u8 ofdm_ht_dual_stream_basic_rates;
u8 ofdm_ht_triple_stream_basic_rates;
u8 reserved2;
__le16 rx_chain_select_flags;
__le16 acquisition_data;
__le32 reserved3;
} __attribute__ ((packed));
/* /*
* REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
*/ */
@ -614,6 +659,9 @@ struct iwl4965_rxon_assoc_cmd {
__le16 reserved; __le16 reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* /*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response) * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
*/ */
@ -897,10 +945,28 @@ struct iwl_addsta_cmd {
/* /*
* REPLY_ADD_STA = 0x18 (response) * REPLY_ADD_STA = 0x18 (response)
*/ */
struct iwl4965_add_sta_resp { struct iwl_add_sta_resp {
u8 status; /* ADD_STA_* */ u8 status; /* ADD_STA_* */
} __attribute__ ((packed)); } __attribute__ ((packed));
#define REM_STA_SUCCESS_MSK 0x1
/*
* REPLY_REM_STA = 0x19 (response)
*/
struct iwl_rem_sta_resp {
u8 status;
} __attribute__ ((packed));
/*
* REPLY_REM_STA = 0x19 (command)
*/
struct iwl_rem_sta_cmd {
u8 num_sta; /* number of removed stations */
u8 reserved[3];
u8 addr[ETH_ALEN]; /* MAC addr of the first station */
u8 reserved2[2];
} __attribute__ ((packed));
/* /*
* REPLY_WEP_KEY = 0x20 * REPLY_WEP_KEY = 0x20
*/ */
@ -1170,7 +1236,7 @@ struct iwl4965_dram_scratch {
/* /*
* REPLY_TX = 0x1c (command) * REPLY_TX = 0x1c (command)
*/ */
struct iwl4965_tx_cmd { struct iwl_tx_cmd {
/* /*
* MPDU byte count: * MPDU byte count:
* MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
@ -1316,6 +1382,15 @@ enum {
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
}; };
static inline int iwl_is_tx_success(u32 status)
{
status &= TX_STATUS_MSK;
return (status == TX_STATUS_SUCCESS)
|| (status == TX_STATUS_DIRECT_DONE);
}
/* ******************************* /* *******************************
* TX aggregation status * TX aggregation status
******************************* */ ******************************* */
@ -1370,6 +1445,11 @@ enum {
* within the sending station (this 4965), rather than whether it was * within the sending station (this 4965), rather than whether it was
* received successfully by the destination station. * received successfully by the destination station.
*/ */
struct agg_tx_status {
__le16 status;
__le16 sequence;
} __attribute__ ((packed));
struct iwl4965_tx_resp { struct iwl4965_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
@ -1404,11 +1484,6 @@ struct iwl4965_tx_resp {
__le32 status; /* TX status (for aggregation status of 1st frame) */ __le32 status; /* TX status (for aggregation status of 1st frame) */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct agg_tx_status {
__le16 status;
__le16 sequence;
} __attribute__ ((packed));
struct iwl4965_tx_resp_agg { struct iwl4965_tx_resp_agg {
u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 reserved1; u8 reserved1;
@ -1423,6 +1498,44 @@ struct iwl4965_tx_resp_agg {
/* of 1st frame) */ /* of 1st frame) */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct iwl5000_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
u8 failure_rts; /* # failures due to unsuccessful RTS */
u8 failure_frame; /* # failures due to no ACK (unused for agg) */
/* For non-agg: Rate at which frame was successful.
* For agg: Rate at which all frames were transmitted. */
__le32 rate_n_flags; /* RATE_MCS_* */
/* For non-agg: RTS + CTS + frame tx attempts time + ACK.
* For agg: RTS + CTS + aggregation tx time + block-ack time. */
__le16 wireless_media_time; /* uSecs */
__le16 reserved;
__le32 pa_power1; /* RF power amplifier measurement (not used) */
__le32 pa_power2;
__le32 tfd_info;
__le16 seq_ctl;
__le16 byte_cnt;
__le32 tlc_info;
/*
* For non-agg: frame status TX_STATUS_*
* For agg: status of 1st frame, AGG_TX_STATE_*; other frame status
* fields follow this one, up to frame_count.
* Bit fields:
* 11- 0: AGG_TX_STATE_* status code
* 15-12: Retry count for 1st frame in aggregation (retries
* occur if tx failed for this frame when it was a
* member of a previous aggregation block). If rate
* scaling is used, retry count indicates the rate
* table entry used for all frames in the new agg.
* 31-16: Sequence # for this frame's Tx cmd (not SSN!)
*/
struct agg_tx_status status; /* TX status (in aggregation -
* status of 1st frame) */
} __attribute__ ((packed));
/* /*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
* *
@ -2109,7 +2222,7 @@ struct iwl4965_scan_cmd {
/* For active scans (set to all-0s for passive scans). /* For active scans (set to all-0s for passive scans).
* Does not include payload. Must specify Tx rate; no rate scaling. */ * Does not include payload. Must specify Tx rate; no rate scaling. */
struct iwl4965_tx_cmd tx_cmd; struct iwl_tx_cmd tx_cmd;
/* For directed active scans (set to all-0s otherwise) */ /* For directed active scans (set to all-0s otherwise) */
struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
@ -2206,7 +2319,7 @@ struct iwl4965_beacon_notif {
* REPLY_TX_BEACON = 0x91 (command, has simple generic response) * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
*/ */
struct iwl4965_tx_beacon_cmd { struct iwl4965_tx_beacon_cmd {
struct iwl4965_tx_cmd tx; struct iwl_tx_cmd tx;
__le16 tim_idx; __le16 tim_idx;
u8 tim_size; u8 tim_size;
u8 reserved1; u8 reserved1;
@ -2729,10 +2842,59 @@ enum {
IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
}; };
enum {
CALIBRATION_CFG_CMD = 0x65,
CALIBRATION_RES_NOTIFICATION = 0x66,
CALIBRATION_COMPLETE_NOTIFICATION = 0x67
};
struct iwl_cal_crystal_freq_cmd {
u8 cap_pin1;
u8 cap_pin2;
} __attribute__ ((packed));
struct iwl5000_calibration {
u8 op_code;
u8 first_group;
u8 num_groups;
u8 all_data_valid;
struct iwl_cal_crystal_freq_cmd data;
} __attribute__ ((packed));
#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff)
struct iwl_calib_cfg_elmnt_s {
__le32 is_enable;
__le32 start;
__le32 send_res;
__le32 apply_res;
__le32 reserved;
} __attribute__ ((packed));
struct iwl_calib_cfg_status_s {
struct iwl_calib_cfg_elmnt_s once;
struct iwl_calib_cfg_elmnt_s perd;
__le32 flags;
} __attribute__ ((packed));
struct iwl5000_calib_cfg_cmd {
struct iwl_calib_cfg_status_s ucd_calib_cfg;
struct iwl_calib_cfg_status_s drv_calib_cfg;
__le32 reserved1;
} __attribute__ ((packed));
struct iwl5000_calib_hdr {
u8 op_code;
u8 first_group;
u8 groups_num;
u8 data_valid;
} __attribute__ ((packed));
struct iwl5000_calibration_chain_noise_reset_cmd { struct iwl5000_calibration_chain_noise_reset_cmd {
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
u8 flags; /* not used */ u8 flags; /* not used */
@ -2771,6 +2933,55 @@ struct iwl4965_led_cmd {
u8 reserved; u8 reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));
/*
* Coexistence WIFI/WIMAX Command
* COEX_PRIORITY_TABLE_CMD = 0x5a
*
*/
enum {
COEX_UNASSOC_IDLE = 0,
COEX_UNASSOC_MANUAL_SCAN = 1,
COEX_UNASSOC_AUTO_SCAN = 2,
COEX_CALIBRATION = 3,
COEX_PERIODIC_CALIBRATION = 4,
COEX_CONNECTION_ESTAB = 5,
COEX_ASSOCIATED_IDLE = 6,
COEX_ASSOC_MANUAL_SCAN = 7,
COEX_ASSOC_AUTO_SCAN = 8,
COEX_ASSOC_ACTIVE_LEVEL = 9,
COEX_RF_ON = 10,
COEX_RF_OFF = 11,
COEX_STAND_ALONE_DEBUG = 12,
COEX_IPAN_ASSOC_LEVEL = 13,
COEX_RSRVD1 = 14,
COEX_RSRVD2 = 15,
COEX_NUM_OF_EVENTS = 16
};
struct iwl_wimax_coex_event_entry {
u8 request_prio;
u8 win_medium_prio;
u8 reserved;
u8 flags;
} __attribute__ ((packed));
/* COEX flag masks */
/* Staion table is valid */
#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1)
/* UnMask wakeup src at unassociated sleep */
#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4)
/* UnMask wakeup src at associated sleep */
#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8)
/* Enable CoEx feature. */
#define COEX_FLAGS_COEX_ENABLE_MSK (0x80)
struct iwl_wimax_coex_cmd {
u8 flags;
u8 reserved[3];
struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
} __attribute__ ((packed));
/****************************************************************************** /******************************************************************************
* (13) * (13)
* Union of all expected notifications/responses: * Union of all expected notifications/responses:
@ -2781,20 +2992,22 @@ struct iwl_rx_packet {
__le32 len; __le32 len;
struct iwl_cmd_header hdr; struct iwl_cmd_header hdr;
union { union {
struct iwl4965_alive_resp alive_frame; struct iwl_alive_resp alive_frame;
struct iwl4965_rx_frame rx_frame; struct iwl4965_rx_frame rx_frame;
struct iwl4965_tx_resp tx_resp; struct iwl4965_tx_resp tx_resp;
struct iwl4965_spectrum_notification spectrum_notif; struct iwl4965_spectrum_notification spectrum_notif;
struct iwl4965_csa_notification csa_notif; struct iwl4965_csa_notification csa_notif;
struct iwl4965_error_resp err_resp; struct iwl_error_resp err_resp;
struct iwl4965_card_state_notif card_state_notif; struct iwl4965_card_state_notif card_state_notif;
struct iwl4965_beacon_notif beacon_status; struct iwl4965_beacon_notif beacon_status;
struct iwl4965_add_sta_resp add_sta; struct iwl_add_sta_resp add_sta;
struct iwl_rem_sta_resp rem_sta;
struct iwl4965_sleep_notification sleep_notif; struct iwl4965_sleep_notification sleep_notif;
struct iwl4965_spectrum_resp spectrum; struct iwl4965_spectrum_resp spectrum;
struct iwl4965_notif_statistics stats; struct iwl4965_notif_statistics stats;
struct iwl4965_compressed_ba_resp compressed_ba; struct iwl4965_compressed_ba_resp compressed_ba;
struct iwl4965_missed_beacon_notif missed_beacon; struct iwl4965_missed_beacon_notif missed_beacon;
struct iwl5000_calibration calib;
__le32 status; __le32 status;
u8 raw[0]; u8 raw[0];
} u; } u;

View File

@ -67,7 +67,7 @@ MODULE_LICENSE("GPL");
* maps to IWL_RATE_INVALID * maps to IWL_RATE_INVALID
* *
*/ */
const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
@ -83,7 +83,12 @@ const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
/* FIXME:RS: ^^ should be INV (legacy) */ /* FIXME:RS: ^^ should be INV (legacy) */
}; };
EXPORT_SYMBOL(iwl4965_rates); EXPORT_SYMBOL(iwl_rates);
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
EXPORT_SYMBOL(iwl_bcast_addr);
/* This function both allocates and initializes hw and priv. */ /* This function both allocates and initializes hw and priv. */
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
@ -317,25 +322,34 @@ void iwl_reset_qos(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_reset_qos); EXPORT_SYMBOL(iwl_reset_qos);
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */
#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_ht_info *ht_info, struct ieee80211_ht_info *ht_info,
enum ieee80211_band band) enum ieee80211_band band)
{ {
u16 max_bit_rate = 0;
u8 rx_chains_num = priv->hw_params.rx_chains_num;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
ht_info->cap = 0; ht_info->cap = 0;
memset(ht_info->supp_mcs_set, 0, 16); memset(ht_info->supp_mcs_set, 0, 16);
ht_info->ht_supported = 1; ht_info->ht_supported = 1;
if (priv->hw_params.fat_channel & BIT(band)) {
ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
ht_info->supp_mcs_set[4] = 0x01;
}
ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
(IWL_MIMO_PS_NONE << 2)); (IWL_MIMO_PS_NONE << 2));
max_bit_rate = MAX_BIT_RATE_20_MHZ;
if (priv->hw_params.fat_channel & BIT(band)) {
ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
ht_info->supp_mcs_set[4] = 0x01;
max_bit_rate = MAX_BIT_RATE_40_MHZ;
}
if (priv->cfg->mod_params->amsdu_size_8K) if (priv->cfg->mod_params->amsdu_size_8K)
ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
@ -343,10 +357,22 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
ht_info->supp_mcs_set[0] = 0xFF; ht_info->supp_mcs_set[0] = 0xFF;
if (priv->hw_params.tx_chains_num >= 2) if (rx_chains_num >= 2)
ht_info->supp_mcs_set[1] = 0xFF; ht_info->supp_mcs_set[1] = 0xFF;
if (priv->hw_params.tx_chains_num >= 3) if (rx_chains_num >= 3)
ht_info->supp_mcs_set[2] = 0xFF; ht_info->supp_mcs_set[2] = 0xFF;
/* Highest supported Rx data rate */
max_bit_rate *= rx_chains_num;
ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
/* Tx MCS capabilities */
ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
if (tx_chains_num != rx_chains_num) {
ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
}
} }
#else #else
static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@ -362,7 +388,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv,
int i; int i;
for (i = 0; i < IWL_RATE_COUNT; i++) { for (i = 0; i < IWL_RATE_COUNT; i++) {
rates[i].bitrate = iwl4965_rates[i].ieee * 5; rates[i].bitrate = iwl_rates[i].ieee * 5;
rates[i].hw_value = i; /* Rate scaling will work on indexes */ rates[i].hw_value = i; /* Rate scaling will work on indexes */
rates[i].hw_value_short = i; rates[i].hw_value_short = i;
rates[i].flags = 0; rates[i].flags = 0;
@ -371,7 +397,7 @@ static void iwlcore_init_hw_rates(struct iwl_priv *priv,
* If CCK != 1M then set short preamble rate flag. * If CCK != 1M then set short preamble rate flag.
*/ */
rates[i].flags |= rates[i].flags |=
(iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ? (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
0 : IEEE80211_RATE_SHORT_PREAMBLE; 0 : IEEE80211_RATE_SHORT_PREAMBLE;
} }
} }
@ -460,6 +486,25 @@ static int iwlcore_init_geos(struct iwl_priv *priv)
if (ch->flags & EEPROM_CHANNEL_RADAR) if (ch->flags & EEPROM_CHANNEL_RADAR)
geo_ch->flags |= IEEE80211_CHAN_RADAR; geo_ch->flags |= IEEE80211_CHAN_RADAR;
switch (ch->fat_extension_channel) {
case HT_IE_EXT_CHANNEL_ABOVE:
/* only above is allowed, disable below */
geo_ch->flags |= IEEE80211_CHAN_NO_FAT_BELOW;
break;
case HT_IE_EXT_CHANNEL_BELOW:
/* only below is allowed, disable above */
geo_ch->flags |= IEEE80211_CHAN_NO_FAT_ABOVE;
break;
case HT_IE_EXT_CHANNEL_NONE:
/* fat not allowed: disable both*/
geo_ch->flags |= (IEEE80211_CHAN_NO_FAT_ABOVE |
IEEE80211_CHAN_NO_FAT_BELOW);
break;
case HT_IE_EXT_CHANNEL_MAX:
/* both above and below are permitted */
break;
}
if (ch->max_power_avg > priv->max_channel_txpower_limit) if (ch->max_power_avg > priv->max_channel_txpower_limit)
priv->max_channel_txpower_limit = priv->max_channel_txpower_limit =
ch->max_power_avg; ch->max_power_avg;
@ -492,12 +537,6 @@ static int iwlcore_init_geos(struct iwl_priv *priv)
priv->bands[IEEE80211_BAND_2GHZ].n_channels, priv->bands[IEEE80211_BAND_2GHZ].n_channels,
priv->bands[IEEE80211_BAND_5GHZ].n_channels); priv->bands[IEEE80211_BAND_5GHZ].n_channels);
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->bands[IEEE80211_BAND_2GHZ];
if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&priv->bands[IEEE80211_BAND_5GHZ];
set_bit(STATUS_GEO_CONFIGURED, &priv->status); set_bit(STATUS_GEO_CONFIGURED, &priv->status);
@ -507,13 +546,12 @@ static int iwlcore_init_geos(struct iwl_priv *priv)
/* /*
* iwlcore_free_geos - undo allocations in iwlcore_init_geos * iwlcore_free_geos - undo allocations in iwlcore_init_geos
*/ */
void iwlcore_free_geos(struct iwl_priv *priv) static void iwlcore_free_geos(struct iwl_priv *priv)
{ {
kfree(priv->ieee_channels); kfree(priv->ieee_channels);
kfree(priv->ieee_rates); kfree(priv->ieee_rates);
clear_bit(STATUS_GEO_CONFIGURED, &priv->status); clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
} }
EXPORT_SYMBOL(iwlcore_free_geos);
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
static u8 is_single_rx_stream(struct iwl_priv *priv) static u8 is_single_rx_stream(struct iwl_priv *priv)
@ -567,7 +605,7 @@ EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
{ {
struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
u32 val; u32 val;
if (!ht_info->is_ht) if (!ht_info->is_ht)
@ -741,8 +779,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv,
} }
EXPORT_SYMBOL(iwl_set_rxon_channel); EXPORT_SYMBOL(iwl_set_rxon_channel);
static void iwlcore_init_hw(struct iwl_priv *priv) int iwl_setup_mac(struct iwl_priv *priv)
{ {
int ret;
struct ieee80211_hw *hw = priv->hw; struct ieee80211_hw *hw = priv->hw;
hw->rate_control_algorithm = "iwl-4965-rs"; hw->rate_control_algorithm = "iwl-4965-rs";
@ -756,9 +795,29 @@ static void iwlcore_init_hw(struct iwl_priv *priv)
/* Enhanced value; more queues, to support 11n aggregation */ /* Enhanced value; more queues, to support 11n aggregation */
hw->ampdu_queues = 12; hw->ampdu_queues = 12;
#endif /* CONFIG_IWL4965_HT */ #endif /* CONFIG_IWL4965_HT */
}
static int iwlcore_init_drv(struct iwl_priv *priv) hw->conf.beacon_int = 100;
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->bands[IEEE80211_BAND_2GHZ];
if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&priv->bands[IEEE80211_BAND_5GHZ];
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERROR("Failed to register hw (error %d)\n", ret);
return ret;
}
priv->mac80211_registered = 1;
return 0;
}
EXPORT_SYMBOL(iwl_setup_mac);
int iwl_init_drv(struct iwl_priv *priv)
{ {
int ret; int ret;
int i; int i;
@ -795,6 +854,9 @@ static int iwlcore_init_drv(struct iwl_priv *priv)
/* Choose which receivers/antennas to use */ /* Choose which receivers/antennas to use */
iwl_set_rxon_chain(priv); iwl_set_rxon_chain(priv);
if (priv->cfg->mod_params->enable_qos)
priv->qos_data.qos_enable = 1;
iwl_reset_qos(priv); iwl_reset_qos(priv);
priv->qos_data.qos_active = 0; priv->qos_data.qos_active = 0;
@ -819,34 +881,39 @@ static int iwlcore_init_drv(struct iwl_priv *priv)
goto err_free_channel_map; goto err_free_channel_map;
} }
ret = ieee80211_register_hw(priv->hw);
if (ret) {
IWL_ERROR("Failed to register network device (error %d)\n",
ret);
goto err_free_geos;
}
priv->hw->conf.beacon_int = 100;
priv->mac80211_registered = 1;
return 0; return 0;
err_free_geos:
iwlcore_free_geos(priv);
err_free_channel_map: err_free_channel_map:
iwl_free_channel_map(priv); iwl_free_channel_map(priv);
err: err:
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_init_drv);
int iwl_setup(struct iwl_priv *priv) void iwl_free_calib_results(struct iwl_priv *priv)
{ {
int ret = 0; kfree(priv->calib_results.lo_res);
iwlcore_init_hw(priv); priv->calib_results.lo_res = NULL;
ret = iwlcore_init_drv(priv); priv->calib_results.lo_res_len = 0;
return ret;
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_setup); EXPORT_SYMBOL(iwl_free_calib_results);
void iwl_uninit_drv(struct iwl_priv *priv)
{
iwl_free_calib_results(priv);
iwlcore_free_geos(priv);
iwl_free_channel_map(priv);
kfree(priv->scan);
}
EXPORT_SYMBOL(iwl_uninit_drv);
/* Low level driver call this function to update iwlcore with /* Low level driver call this function to update iwlcore with
* driver status. * driver status.
@ -1024,3 +1091,185 @@ int iwl_verify_ucode(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwl_verify_ucode); EXPORT_SYMBOL(iwl_verify_ucode);
static const char *desc_lookup(int i)
{
switch (i) {
case 1:
return "FAIL";
case 2:
return "BAD_PARAM";
case 3:
return "BAD_CHECKSUM";
case 4:
return "NMI_INTERRUPT";
case 5:
return "SYSASSERT";
case 6:
return "FATAL_ERROR";
}
return "UNKNOWN";
}
#define ERROR_START_OFFSET (1 * sizeof(u32))
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
void iwl_dump_nic_error_log(struct iwl_priv *priv)
{
u32 data2, line;
u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2;
int ret;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
return;
}
ret = iwl_grab_nic_access(priv);
if (ret) {
IWL_WARNING("Can not read from adapter at this time.\n");
return;
}
count = iwl_read_targ_mem(priv, base);
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERROR("Start IWL Error Log Dump:\n");
IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
}
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
IWL_ERROR("Desc Time "
"data1 data2 line\n");
IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
desc_lookup(desc), desc, time, data1, data2, line);
IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
ilink1, ilink2);
iwl_release_nic_access(priv);
}
EXPORT_SYMBOL(iwl_dump_nic_error_log);
#define EVENT_START_OFFSET (4 * sizeof(u32))
/**
* iwl_print_event_log - Dump error event log to syslog
*
* NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
*/
void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode)
{
u32 i;
u32 base; /* SRAM byte address of event log header */
u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
u32 ptr; /* SRAM byte address of log data */
u32 ev, time, data; /* event log data */
if (num_events == 0)
return;
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (mode == 0)
event_size = 2 * sizeof(u32);
else
event_size = 3 * sizeof(u32);
ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
ev = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
time = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
if (mode == 0)
IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
else {
data = iwl_read_targ_mem(priv, ptr);
ptr += sizeof(u32);
IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
}
}
}
EXPORT_SYMBOL(iwl_print_event_log);
void iwl_dump_nic_event_log(struct iwl_priv *priv)
{
int ret;
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
if (priv->ucode_type == UCODE_INIT)
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
return;
}
ret = iwl_grab_nic_access(priv);
if (ret) {
IWL_WARNING("Can not read from adapter at this time.\n");
return;
}
/* event log header */
capacity = iwl_read_targ_mem(priv, base);
mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
size = num_wraps ? capacity : next_entry;
/* bail out if nothing in log */
if (size == 0) {
IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
iwl_release_nic_access(priv);
return;
}
IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
size, num_wraps);
/* if uCode has wrapped back to top of log, start at the oldest entry,
* i.e the next one that uCode would fill. */
if (num_wraps)
iwl_print_event_log(priv, next_entry,
capacity - next_entry, mode);
/* (then/else) start at top of log */
iwl_print_event_log(priv, 0, next_entry, mode);
iwl_release_nic_access(priv);
}
EXPORT_SYMBOL(iwl_dump_nic_event_log);

View File

@ -86,7 +86,7 @@ struct iwl_hcmd_ops {
int (*rxon_assoc)(struct iwl_priv *priv); int (*rxon_assoc)(struct iwl_priv *priv);
}; };
struct iwl_hcmd_utils_ops { struct iwl_hcmd_utils_ops {
int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data); u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
void (*gain_computation)(struct iwl_priv *priv, void (*gain_computation)(struct iwl_priv *priv,
@ -104,13 +104,22 @@ struct iwl_lib_ops {
int (*alloc_shared_mem)(struct iwl_priv *priv); int (*alloc_shared_mem)(struct iwl_priv *priv);
void (*free_shared_mem)(struct iwl_priv *priv); void (*free_shared_mem)(struct iwl_priv *priv);
int (*shared_mem_rx_idx)(struct iwl_priv *priv); int (*shared_mem_rx_idx)(struct iwl_priv *priv);
/* Handling TX */
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
struct iwl_tx_queue *txq, struct iwl_tx_queue *txq,
u16 byte_cnt); u16 byte_cnt);
void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
#ifdef CONFIG_IWL4965_HT
/* aggregations */
int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
int sta_id, int tid, u16 ssn_idx);
int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
u8 tx_fifo);
#endif /* CONFIG_IWL4965_HT */
/* setup Rx handler */ /* setup Rx handler */
void (*rx_handler_setup)(struct iwl_priv *priv); void (*rx_handler_setup)(struct iwl_priv *priv);
/* nic Tx fifo handling */
int (*disable_tx_fifo)(struct iwl_priv *priv);
/* alive notification after init uCode load */ /* alive notification after init uCode load */
void (*init_alive_start)(struct iwl_priv *priv); void (*init_alive_start)(struct iwl_priv *priv);
/* alive notification */ /* alive notification */
@ -124,6 +133,8 @@ struct iwl_lib_ops {
/* power management */ /* power management */
struct { struct {
int (*init)(struct iwl_priv *priv); int (*init)(struct iwl_priv *priv);
int (*reset)(struct iwl_priv *priv);
void (*stop)(struct iwl_priv *priv);
void (*config)(struct iwl_priv *priv); void (*config)(struct iwl_priv *priv);
int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
} apm_ops; } apm_ops;
@ -170,18 +181,19 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
void iwl_hw_detect(struct iwl_priv *priv); void iwl_hw_detect(struct iwl_priv *priv);
void iwlcore_clear_stations_table(struct iwl_priv *priv); void iwlcore_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_reset_qos(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, int iwl_set_rxon_channel(struct iwl_priv *priv,
enum ieee80211_band band, enum ieee80211_band band,
u16 channel); u16 channel);
void iwlcore_free_geos(struct iwl_priv *priv);
int iwl_setup(struct iwl_priv *priv);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); 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, u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
struct ieee80211_ht_info *sta_ht_inf); struct ieee80211_ht_info *sta_ht_inf);
int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_hw_nic_init(struct iwl_priv *priv);
int iwl_setup_mac(struct iwl_priv *priv);
int iwl_init_drv(struct iwl_priv *priv);
void iwl_uninit_drv(struct iwl_priv *priv);
/* "keep warm" functions */ /* "keep warm" functions */
int iwl_kw_init(struct iwl_priv *priv); int iwl_kw_init(struct iwl_priv *priv);
int iwl_kw_alloc(struct iwl_priv *priv); int iwl_kw_alloc(struct iwl_priv *priv);
@ -202,14 +214,30 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q); int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv); void iwl_rx_allocate(struct iwl_priv *priv);
void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
/* Handlers */
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
/* TX helpers */
/***************************************************** /*****************************************************
* TX * TX
******************************************************/ ******************************************************/
int iwl_txq_ctx_reset(struct iwl_priv *priv); int iwl_txq_ctx_reset(struct iwl_priv *priv);
int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
/* FIXME: remove when free Tx is fully merged into iwlcore */ /* FIXME: remove when free Tx is fully merged into iwlcore */
int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
void iwl_hw_txq_ctx_free(struct iwl_priv *priv); void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
dma_addr_t addr, u16 len);
int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
#ifdef CONFIG_IWL4965_HT
int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
#endif
/***************************************************** /*****************************************************
* S e n d i n g H o s t C o m m a n d s * * S e n d i n g H o s t C o m m a n d s *
@ -226,6 +254,17 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
int (*callback)(struct iwl_priv *priv, int (*callback)(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_cmd *cmd,
struct sk_buff *skb)); struct sk_buff *skb));
int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
/*****************************************************
* Error Handling Debugging
******************************************************/
void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
u32 num_events, u32 mode);
void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
/*************** DRIVER STATUS FUNCTIONS *****/ /*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */
@ -303,5 +342,10 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
return priv->cfg->ops->hcmd->rxon_assoc(priv); return priv->cfg->ops->hcmd->rxon_assoc(priv);
} }
static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
struct iwl_priv *priv, enum ieee80211_band band)
{
return priv->hw->wiphy->bands[band];
}
#endif /* __iwl_core_h__ */ #endif /* __iwl_core_h__ */

View File

@ -87,13 +87,14 @@
/* EEPROM reads */ /* EEPROM reads */
#define CSR_EEPROM_REG (CSR_BASE+0x02c) #define CSR_EEPROM_REG (CSR_BASE+0x02c)
#define CSR_EEPROM_GP (CSR_BASE+0x030) #define CSR_EEPROM_GP (CSR_BASE+0x030)
#define CSR_GIO_REG (CSR_BASE+0x03C)
#define CSR_GP_UCODE (CSR_BASE+0x044) #define CSR_GP_UCODE (CSR_BASE+0x044)
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) #define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
#define CSR_LED_REG (CSR_BASE+0x094) #define CSR_LED_REG (CSR_BASE+0x094)
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
/* Analog phase-lock-loop configuration */ /* Analog phase-lock-loop configuration */
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
@ -213,6 +214,9 @@
#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
/* CSR GIO */
#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
/* UCODE DRV GP */ /* UCODE DRV GP */
#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) #define CSR_UCODE_SW_BIT_RFKILL (0x00000002)

View File

@ -45,13 +45,21 @@ struct iwl_debugfs {
const char *name; const char *name;
struct dentry *dir_drv; struct dentry *dir_drv;
struct dentry *dir_data; struct dentry *dir_data;
struct dir_data_files{ struct dentry *dir_rf;
struct dir_data_files {
struct dentry *file_sram; struct dentry *file_sram;
struct dentry *file_eeprom; struct dentry *file_eeprom;
struct dentry *file_stations; struct dentry *file_stations;
struct dentry *file_rx_statistics; struct dentry *file_rx_statistics;
struct dentry *file_tx_statistics; struct dentry *file_tx_statistics;
struct dentry *file_log_event;
} dbgfs_data_files; } dbgfs_data_files;
struct dir_rf_files {
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
struct dentry *file_disable_sensitivity;
struct dentry *file_disable_chain_noise;
#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
} dbgfs_rf_files;
u32 sram_offset; u32 sram_offset;
u32 sram_len; u32 sram_len;
}; };

View File

@ -55,6 +55,13 @@
goto err; \ goto err; \
} while (0) } while (0)
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \
} while (0)
#define DEBUGFS_REMOVE(name) do { \ #define DEBUGFS_REMOVE(name) do { \
debugfs_remove(name); \ debugfs_remove(name); \
name = NULL; \ name = NULL; \
@ -85,6 +92,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
.open = iwl_dbgfs_open_file_generic, \ .open = iwl_dbgfs_open_file_generic, \
}; };
#define DEBUGFS_WRITE_FILE_OPS(name) \
DEBUGFS_WRITE_FUNC(name); \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.open = iwl_dbgfs_open_file_generic, \
};
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ #define DEBUGFS_READ_WRITE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name); \ DEBUGFS_READ_FUNC(name); \
DEBUGFS_WRITE_FUNC(name); \ DEBUGFS_WRITE_FUNC(name); \
@ -317,7 +332,29 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
return ret; return ret;
} }
static ssize_t iwl_dbgfs_log_event_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
u32 event_log_flag;
char buf[8];
int buf_size;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d", &event_log_flag) != 1)
return -EFAULT;
if (event_log_flag == 1)
iwl_dump_nic_event_log(priv);
return count;
}
DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(eeprom);
DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(rx_statistics);
@ -330,6 +367,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
{ {
struct iwl_debugfs *dbgfs; struct iwl_debugfs *dbgfs;
struct dentry *phyd = priv->hw->wiphy->debugfsdir;
dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
if (!dbgfs) { if (!dbgfs) {
@ -338,18 +376,24 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
priv->dbgfs = dbgfs; priv->dbgfs = dbgfs;
dbgfs->name = name; dbgfs->name = name;
dbgfs->dir_drv = debugfs_create_dir(name, NULL); dbgfs->dir_drv = debugfs_create_dir(name, phyd);
if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){
goto err; goto err;
} }
DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
DEBUGFS_ADD_FILE(eeprom, data); DEBUGFS_ADD_FILE(eeprom, data);
DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(sram, data);
DEBUGFS_ADD_FILE(log_event, data);
DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(stations, data);
DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(rx_statistics, data);
DEBUGFS_ADD_FILE(tx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data);
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
return 0; return 0;
err: err:
@ -372,8 +416,14 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dir_data);
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv); DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs); kfree(priv->dbgfs);
priv->dbgfs = NULL; priv->dbgfs = NULL;
@ -381,3 +431,4 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_dbgfs_unregister); EXPORT_SYMBOL(iwl_dbgfs_unregister);

View File

@ -102,7 +102,7 @@ struct iwl_rx_mem_buffer {
* *
* Contains common data for Rx and Tx queues * Contains common data for Rx and Tx queues
*/ */
struct iwl4965_queue { struct iwl_queue {
int n_bd; /* number of BDs in this queue */ int n_bd; /* number of BDs in this queue */
int write_ptr; /* 1-st empty entry (index) host_w*/ int write_ptr; /* 1-st empty entry (index) host_w*/
int read_ptr; /* last used entry (index) host_r*/ int read_ptr; /* last used entry (index) host_r*/
@ -118,8 +118,7 @@ struct iwl4965_queue {
#define MAX_NUM_OF_TBS (20) #define MAX_NUM_OF_TBS (20)
/* One for each TFD */ /* One for each TFD */
struct iwl4965_tx_info { struct iwl_tx_info {
struct ieee80211_tx_status status;
struct sk_buff *skb[MAX_NUM_OF_TBS]; struct sk_buff *skb[MAX_NUM_OF_TBS];
}; };
@ -137,11 +136,11 @@ struct iwl4965_tx_info {
* descriptors) and required locking structures. * descriptors) and required locking structures.
*/ */
struct iwl_tx_queue { struct iwl_tx_queue {
struct iwl4965_queue q; struct iwl_queue q;
struct iwl_tfd_frame *bd; struct iwl_tfd_frame *bd;
struct iwl_cmd *cmd; struct iwl_cmd *cmd;
dma_addr_t dma_addr_cmd; dma_addr_t dma_addr_cmd;
struct iwl4965_tx_info *txb; struct iwl_tx_info *txb;
int need_update; int need_update;
int sched_retry; int sched_retry;
int active; int active;
@ -262,7 +261,7 @@ enum iwl_pwr_src {
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
struct iwl4965_frame { struct iwl_frame {
union { union {
struct ieee80211_hdr frame; struct ieee80211_hdr frame;
struct iwl4965_tx_beacon_cmd beacon; struct iwl4965_tx_beacon_cmd beacon;
@ -308,6 +307,8 @@ struct iwl_cmd_meta {
} __attribute__ ((packed)); } __attribute__ ((packed));
#define IWL_CMD_MAX_PAYLOAD 320
/** /**
* struct iwl_cmd * struct iwl_cmd
* *
@ -329,11 +330,12 @@ struct iwl_cmd {
struct iwl4965_rxon_time_cmd rxon_time; struct iwl4965_rxon_time_cmd rxon_time;
struct iwl4965_powertable_cmd powertable; struct iwl4965_powertable_cmd powertable;
struct iwl4965_qosparam_cmd qosparam; struct iwl4965_qosparam_cmd qosparam;
struct iwl4965_tx_cmd tx; struct iwl_tx_cmd tx;
struct iwl4965_tx_beacon_cmd tx_beacon; struct iwl4965_tx_beacon_cmd tx_beacon;
struct iwl4965_rxon_assoc_cmd rxon_assoc; struct iwl4965_rxon_assoc_cmd rxon_assoc;
struct iwl_rem_sta_cmd rm_sta;
u8 *indirect; u8 *indirect;
u8 payload[360]; u8 payload[IWL_CMD_MAX_PAYLOAD];
} __attribute__ ((packed)) cmd; } __attribute__ ((packed)) cmd;
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -442,7 +444,6 @@ struct iwl_hw_key {
enum ieee80211_key_alg alg; enum ieee80211_key_alg alg;
int keylen; int keylen;
u8 keyidx; u8 keyidx;
struct ieee80211_key_conf *conf;
u8 key[32]; u8 key[32];
}; };
@ -573,7 +574,6 @@ struct iwl_sensitivity_ranges {
/** /**
* struct iwl_hw_params * struct iwl_hw_params
* @max_txq_num: Max # Tx queues supported * @max_txq_num: Max # Tx queues supported
* @tx_cmd_len: Size of Tx command (but not including frame itself)
* @tx/rx_chains_num: Number of TX/RX chains * @tx/rx_chains_num: Number of TX/RX chains
* @valid_tx/rx_ant: usable antennas * @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
@ -590,7 +590,6 @@ struct iwl_sensitivity_ranges {
*/ */
struct iwl_hw_params { struct iwl_hw_params {
u16 max_txq_num; u16 max_txq_num;
u16 tx_cmd_len;
u8 tx_chains_num; u8 tx_chains_num;
u8 rx_chains_num; u8 rx_chains_num;
u8 valid_tx_ant; u8 valid_tx_ant;
@ -612,8 +611,8 @@ struct iwl_hw_params {
#endif #endif
}; };
#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) #define HT_SHORT_GI_20MHZ (1 << 0)
#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) #define HT_SHORT_GI_40MHZ (1 << 1)
#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
@ -635,8 +634,8 @@ struct iwl_hw_params {
struct iwl_addsta_cmd; struct iwl_addsta_cmd;
extern int iwl_send_add_sta(struct iwl_priv *priv, extern int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags); struct iwl_addsta_cmd *sta, u8 flags);
extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
int is_ap, u8 flags, void *ht_data); u8 flags, struct ieee80211_ht_info *ht_info);
extern int iwl4965_is_network_packet(struct iwl_priv *priv, extern int iwl4965_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header); struct ieee80211_hdr *header);
extern int iwl4965_power_init_handle(struct iwl_priv *priv); extern int iwl4965_power_init_handle(struct iwl_priv *priv);
@ -652,14 +651,13 @@ extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
const u8 *dest, int left); const u8 *dest, int left);
extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
extern void iwl4965_update_chain_flags(struct iwl_priv *priv); extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
int iwl4965_init_geos(struct iwl_priv *priv); int iwl4965_init_geos(struct iwl_priv *priv);
void iwl4965_free_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv);
extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; extern const u8 iwl_bcast_addr[ETH_ALEN];
int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
/* /*
@ -687,19 +685,15 @@ extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id,
****************************************************************************/ ****************************************************************************/
extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv); extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv);
extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv);
extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv); extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv);
extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv); extern int iwl_rxq_stop(struct iwl_priv *priv);
extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
extern int iwl4965_hw_nic_reset(struct iwl_priv *priv);
extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
dma_addr_t addr, u16 len);
extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern int iwl4965_hw_get_temperature(struct iwl_priv *priv);
extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl4965_frame *frame, u8 rate); struct iwl_frame *frame, u8 rate);
extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_cmd *cmd,
struct ieee80211_tx_control *ctrl, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
int sta_id, int tx_id); int sta_id, int tx_id);
extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv);
@ -708,6 +702,8 @@ extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb); struct iwl_rx_mem_buffer *rxb);
extern void iwl4965_disable_events(struct iwl_priv *priv); extern void iwl4965_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv);
extern void iwl4965_rx_reply_rx(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
/** /**
* iwl_find_station - Find station id for a given BSSID * iwl_find_station - Find station id for a given BSSID
@ -720,8 +716,26 @@ extern int iwl4965_get_temperature(const struct iwl_priv *priv);
extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid); extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel); extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel);
extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); extern int iwl_queue_space(const struct iwl_queue *q);
extern int iwl4965_queue_space(const struct iwl4965_queue *q); static inline int iwl_queue_used(const struct iwl_queue *q, int i)
{
return q->write_ptr > q->read_ptr ?
(i >= q->read_ptr && i < q->write_ptr) :
!(i < q->read_ptr && i >= q->write_ptr);
}
static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
{
/* This is for scan command, the big buffer at end of command array */
if (is_huge)
return q->n_window; /* must be power of 2 */
/* Otherwise, use normal size buffers */
return index & (q->n_window - 1);
}
struct iwl_priv; struct iwl_priv;
extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
@ -731,14 +745,12 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
struct iwl_tx_queue *txq, struct iwl_tx_queue *txq,
u16 byte_cnt); u16 byte_cnt);
extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
int is_ap);
extern int iwl4965_alive_notify(struct iwl_priv *priv); extern int iwl4965_alive_notify(struct iwl_priv *priv);
extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv,
u32 rate_n_flags, u32 rate_n_flags,
struct ieee80211_tx_control *control); struct ieee80211_tx_info *info);
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv, extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
@ -746,8 +758,6 @@ extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
enum ieee80211_band band); enum ieee80211_band band);
void iwl4965_set_rxon_ht(struct iwl_priv *priv, void iwl4965_set_rxon_ht(struct iwl_priv *priv,
struct iwl_ht_info *ht_info); struct iwl_ht_info *ht_info);
void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_ht_info *sta_ht_inf);
int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
const u8 *addr, u16 tid, u16 *ssn); const u8 *addr, u16 tid, u16 *ssn);
@ -867,6 +877,21 @@ struct statistics_general_data {
u32 beacon_energy_c; 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;
};
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
UCODE_RT
};
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
/* Sensitivity calib data */ /* Sensitivity calib data */
struct iwl_sensitivity_data { struct iwl_sensitivity_data {
@ -968,6 +993,9 @@ struct iwl_priv {
s32 temperature; /* degrees Kelvin */ s32 temperature; /* degrees Kelvin */
s32 last_temperature; s32 last_temperature;
/* init calibration results */
struct iwl_calib_results calib_results;
/* Scan related variables */ /* Scan related variables */
unsigned long last_scan_jiffies; unsigned long last_scan_jiffies;
unsigned long next_scan_jiffies; unsigned long next_scan_jiffies;
@ -1001,6 +1029,8 @@ struct iwl_priv {
struct fw_desc ucode_init; /* initialization inst */ struct fw_desc ucode_init; /* initialization inst */
struct fw_desc ucode_init_data; /* initialization data */ struct fw_desc ucode_init_data; /* initialization data */
struct fw_desc ucode_boot; /* bootstrap inst */ struct fw_desc ucode_boot; /* bootstrap inst */
enum ucode_type ucode_type;
u8 ucode_write_complete; /* the image write is complete */
struct iwl4965_rxon_time_cmd rxon_timing; struct iwl4965_rxon_time_cmd rxon_timing;
@ -1009,16 +1039,16 @@ struct iwl_priv {
* changed via explicit cast within the * changed via explicit cast within the
* routines that actually update the physical * routines that actually update the physical
* hardware */ * hardware */
const struct iwl4965_rxon_cmd active_rxon; const struct iwl_rxon_cmd active_rxon;
struct iwl4965_rxon_cmd staging_rxon; struct iwl_rxon_cmd staging_rxon;
int error_recovering; int error_recovering;
struct iwl4965_rxon_cmd recovery_rxon; struct iwl_rxon_cmd recovery_rxon;
/* 1st responses from initialize and runtime uCode images. /* 1st responses from initialize and runtime uCode images.
* 4965's initialize alive response contains some calibration data. */ * 4965's initialize alive response contains some calibration data. */
struct iwl4965_init_alive_resp card_alive_init; struct iwl_init_alive_resp card_alive_init;
struct iwl4965_alive_resp card_alive; struct iwl_alive_resp card_alive;
#ifdef CONFIG_IWLWIFI_RFKILL #ifdef CONFIG_IWLWIFI_RFKILL
struct iwl_rfkill_mngr rfkill_mngr; struct iwl_rfkill_mngr rfkill_mngr;
#endif #endif
@ -1107,8 +1137,6 @@ struct iwl_priv {
u8 mac80211_registered; u8 mac80211_registered;
u32 notif_missed_beacons;
/* Rx'd packet timing information */ /* Rx'd packet timing information */
u32 last_beacon_time; u32 last_beacon_time;
u64 last_tsf; u64 last_tsf;
@ -1195,12 +1223,56 @@ struct iwl_priv {
#endif /* CONFIG_IWLWIFI_DEBUG */ #endif /* CONFIG_IWLWIFI_DEBUG */
struct work_struct txpower_work; struct work_struct txpower_work;
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
u32 disable_sens_cal;
u32 disable_chain_noise_cal;
#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
#ifdef CONFIG_IWL4965_RUN_TIME_CALIB #ifdef CONFIG_IWL4965_RUN_TIME_CALIB
struct work_struct sensitivity_work; struct work_struct sensitivity_work;
#endif #endif /* CONFIG_IWL4965_RUN_TIME_CALIB */
struct timer_list statistics_periodic; struct timer_list statistics_periodic;
}; /*iwl_priv */ }; /*iwl_priv */
static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
{
set_bit(txq_id, &priv->txq_ctx_active_msk);
}
static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
{
clear_bit(txq_id, &priv->txq_ctx_active_msk);
}
#ifdef CONFIG_IWLWIF_DEBUG
const char *iwl_get_tx_fail_reason(u32 status);
#else
static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
#endif
#ifdef CONFIG_IWL4965_HT
static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
struct ieee80211_hdr *hdr)
{
if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
return IWL_AP_ID;
} else {
u8 *da = ieee80211_get_DA(hdr);
return iwl_find_station(priv, da);
}
}
static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
int txq_id, int idx)
{
if (priv->txq[txq_id].txb[idx].skb[0])
return (struct ieee80211_hdr *)priv->txq[txq_id].
txb[idx].skb[0]->data;
return NULL;
}
#endif
static inline int iwl_is_associated(struct iwl_priv *priv) static inline int iwl_is_associated(struct iwl_priv *priv)
{ {
return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;

View File

@ -365,11 +365,11 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
? # x " " : "") ? # x " " : "")
/** /**
* iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. * iwl_set_fat_chan_info - Copy fat channel info into driver's priv.
* *
* Does not set up a command, or touch hardware. * Does not set up a command, or touch hardware.
*/ */
static int iwl4965_set_fat_chan_info(struct iwl_priv *priv, static int iwl_set_fat_chan_info(struct iwl_priv *priv,
enum ieee80211_band band, u16 channel, enum ieee80211_band band, u16 channel,
const struct iwl_eeprom_channel *eeprom_ch, const struct iwl_eeprom_channel *eeprom_ch,
u8 fat_extension_channel) u8 fat_extension_channel)
@ -542,16 +542,16 @@ int iwl_init_channel_map(struct iwl_priv *priv)
fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
/* Set up driver's info for lower half */ /* Set up driver's info for lower half */
iwl4965_set_fat_chan_info(priv, ieeeband, iwl_set_fat_chan_info(priv, ieeeband,
eeprom_ch_index[ch], eeprom_ch_index[ch],
&(eeprom_ch_info[ch]), &(eeprom_ch_info[ch]),
fat_extension_chan); fat_extension_chan);
/* Set up driver's info for upper half */ /* Set up driver's info for upper half */
iwl4965_set_fat_chan_info(priv, ieeeband, iwl_set_fat_chan_info(priv, ieeeband,
(eeprom_ch_index[ch] + 4), (eeprom_ch_index[ch] + 4),
&(eeprom_ch_info[ch]), &(eeprom_ch_info[ch]),
HT_IE_EXT_CHANNEL_BELOW); HT_IE_EXT_CHANNEL_BELOW);
} }
} }
@ -560,23 +560,21 @@ int iwl_init_channel_map(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_init_channel_map); EXPORT_SYMBOL(iwl_init_channel_map);
/* /*
* iwl_free_channel_map - undo allocations in iwl4965_init_channel_map * iwl_free_channel_map - undo allocations in iwl_init_channel_map
*/ */
void iwl_free_channel_map(struct iwl_priv *priv) void iwl_free_channel_map(struct iwl_priv *priv)
{ {
kfree(priv->channel_info); kfree(priv->channel_info);
priv->channel_count = 0; priv->channel_count = 0;
} }
EXPORT_SYMBOL(iwl_free_channel_map);
/** /**
* iwl_get_channel_info - Find driver's private channel info * iwl_get_channel_info - Find driver's private channel info
* *
* Based on band and channel number. * Based on band and channel number.
*/ */
const struct iwl_channel_info *iwl_get_channel_info( const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
const struct iwl_priv *priv, enum ieee80211_band band, u16 channel)
enum ieee80211_band band, u16 channel)
{ {
int i; int i;

View File

@ -146,6 +146,7 @@ struct iwl_eeprom_channel {
/*5000 calibrations */ /*5000 calibrations */
#define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL)
/* 5000 links */ /* 5000 links */
#define EEPROM_5000_LINK_HOST (2*0x64) #define EEPROM_5000_LINK_HOST (2*0x64)

View File

@ -56,6 +56,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_RATE_SCALE); IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD); IWL_CMD(REPLY_LEDS_CMD);
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
IWL_CMD(RADAR_NOTIFICATION); IWL_CMD(RADAR_NOTIFICATION);
IWL_CMD(REPLY_QUIET_CMD); IWL_CMD(REPLY_QUIET_CMD);
IWL_CMD(REPLY_CHANNEL_SWITCH); IWL_CMD(REPLY_CHANNEL_SWITCH);
@ -89,6 +90,9 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_RX_MPDU_CMD); IWL_CMD(REPLY_RX_MPDU_CMD);
IWL_CMD(REPLY_RX); IWL_CMD(REPLY_RX);
IWL_CMD(REPLY_COMPRESSED_BA); IWL_CMD(REPLY_COMPRESSED_BA);
IWL_CMD(CALIBRATION_CFG_CMD);
IWL_CMD(CALIBRATION_RES_NOTIFICATION);
IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
default: default:
return "UNKNOWN"; return "UNKNOWN";
@ -139,7 +143,7 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EBUSY; return -EBUSY;
ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); ret = iwl_enqueue_hcmd(priv, cmd);
if (ret < 0) { if (ret < 0) {
IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(cmd->id), ret); get_cmd_string(cmd->id), ret);
@ -170,7 +174,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
if (cmd->meta.flags & CMD_WANT_SKB) if (cmd->meta.flags & CMD_WANT_SKB)
cmd->meta.source = &cmd->meta; cmd->meta.source = &cmd->meta;
cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) { if (cmd_idx < 0) {
ret = cmd_idx; ret = cmd_idx;
IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",

View File

@ -136,6 +136,8 @@ static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
#define KELVIN_TO_CELSIUS(x) ((x)-273) #define KELVIN_TO_CELSIUS(x) ((x)-273)
#define CELSIUS_TO_KELVIN(x) ((x)+273) #define CELSIUS_TO_KELVIN(x) ((x)+273)
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010 #define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
@ -235,6 +237,25 @@ static inline int ieee80211_is_reassoc_response(u16 fc)
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP); ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
} }
static inline int ieee80211_is_qos_data(u16 fc)
{
return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA);
}
/**
* ieee80211_get_qos_ctrl - get pointer to the QoS control field
*
* This function returns the pointer to 802.11 header QoS field (2 bytes)
* This function doesn't check whether hdr is a QoS hdr, use with care
* @hdr: struct ieee80211_hdr *hdr
* @hdr_len: header length
*/
static inline u8 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr, int hdr_len)
{
return ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
}
static inline int iwl_check_bits(unsigned long field, unsigned long mask) static inline int iwl_check_bits(unsigned long field, unsigned long mask)
{ {
return ((field & mask) == mask) ? 1 : 0; return ((field & mask) == mask) ? 1 : 0;

View File

@ -358,11 +358,6 @@
* 7- 0: Enable (1), disable (0), one bit for each channel 0-7 * 7- 0: Enable (1), disable (0), one bit for each channel 0-7
*/ */
#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c) #define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c)
/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */
#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
/* /*
* Queue (x) Write Pointers (indexes, really!), one for each Tx queue. * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
* Initialized and updated by driver as new TFDs are added to queue. * Initialized and updated by driver as new TFDs are added to queue.
@ -512,11 +507,39 @@
#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ #define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
#define IWL49_SCD_TXFIFO_POS_TID (0) #define IWL_SCD_TXFIFO_POS_TID (0)
#define IWL49_SCD_TXFIFO_POS_RA (4) #define IWL_SCD_TXFIFO_POS_RA (4)
#define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
/* 5000 SCD */ /* 5000 SCD */
#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0)
#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE (3)
#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL (4)
#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
#define IWL50_SCD_QUEUE_STTS_REG_MSK (0x00FF0000)
#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0)
#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
#define IWL50_SCD_CONTEXT_DATA_OFFSET (0x600)
#define IWL50_SCD_TX_STTS_BITMAP_OFFSET (0x7B1)
#define IWL50_SCD_TRANSLATE_TBL_OFFSET (0x7E0)
#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\
(IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\
(~(1<<IWL_CMD_QUEUE_NUM)))
#define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00) #define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00)
#define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0) #define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0)

View File

@ -33,6 +33,7 @@
#include "iwl-core.h" #include "iwl-core.h"
#include "iwl-sta.h" #include "iwl-sta.h"
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-calib.h"
#include "iwl-helpers.h" #include "iwl-helpers.h"
/************************** RX-FUNCTIONS ****************************/ /************************** RX-FUNCTIONS ****************************/
/* /*
@ -420,3 +421,50 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
return 0; return 0;
} }
int iwl_rxq_stop(struct iwl_priv *priv)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (unlikely(ret)) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* stop Rx DMA */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
(1 << 24), 1000);
if (ret < 0)
IWL_ERROR("Can't stop Rx DMA.\n");
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
EXPORT_SYMBOL(iwl_rxq_stop);
void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon;
if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
le32_to_cpu(missed_beacon->consequtive_missed_beacons),
le32_to_cpu(missed_beacon->total_missed_becons),
le32_to_cpu(missed_beacon->num_recvd_beacons),
le32_to_cpu(missed_beacon->num_expected_beacons));
if (!test_bit(STATUS_SCANNING, &priv->status))
iwl_init_sensitivity(priv);
}
#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
}
EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);

View File

@ -37,6 +37,10 @@
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-helpers.h" #include "iwl-helpers.h"
#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */
#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */
u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
{ {
int i; int i;
@ -70,6 +74,39 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
} }
EXPORT_SYMBOL(iwl_find_station); EXPORT_SYMBOL(iwl_find_station);
static int iwl_add_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
if (!skb) {
IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
return 1;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
return 1;
}
switch (res->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
/* FIXME: implement iwl_sta_ucode_activate(priv, addr); */
/* fail through */
default:
IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
res->u.add_sta.status);
break;
}
/* We didn't cache the SKB; let the caller free it */
return 1;
}
int iwl_send_add_sta(struct iwl_priv *priv, int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags) struct iwl_addsta_cmd *sta, u8 flags)
{ {
@ -82,7 +119,9 @@ int iwl_send_add_sta(struct iwl_priv *priv,
.data = data, .data = data,
}; };
if (!(flags & CMD_ASYNC)) if (flags & CMD_ASYNC)
cmd.meta.u.callback = iwl_add_sta_callback;
else
cmd.meta.flags |= CMD_WANT_SKB; cmd.meta.flags |= CMD_WANT_SKB;
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
@ -117,6 +156,276 @@ int iwl_send_add_sta(struct iwl_priv *priv,
} }
EXPORT_SYMBOL(iwl_send_add_sta); EXPORT_SYMBOL(iwl_send_add_sta);
#ifdef CONFIG_IWL4965_HT
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_ht_info *sta_ht_inf)
{
__le32 sta_flags;
u8 mimo_ps_mode;
if (!sta_ht_inf || !sta_ht_inf->ht_supported)
goto done;
mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
sta_flags = priv->stations[index].sta.station_flags;
sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
switch (mimo_ps_mode) {
case WLAN_HT_CAP_MIMO_PS_STATIC:
sta_flags |= STA_FLG_MIMO_DIS_MSK;
break;
case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
break;
case WLAN_HT_CAP_MIMO_PS_DISABLED:
break;
default:
IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
break;
}
sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
sta_flags |= STA_FLG_FAT_EN_MSK;
else
sta_flags &= ~STA_FLG_FAT_EN_MSK;
priv->stations[index].sta.station_flags = sta_flags;
done:
return;
}
#else
static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_ht_info *sta_ht_info)
{
}
#endif
/**
* iwl_add_station_flags - Add station to tables in driver and device
*/
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
u8 flags, struct ieee80211_ht_info *ht_info)
{
int i;
int index = IWL_INVALID_STATION;
struct iwl_station_entry *station;
unsigned long flags_spin;
DECLARE_MAC_BUF(mac);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
if (is_ap)
index = IWL_AP_ID;
else if (is_broadcast_ether_addr(addr))
index = priv->hw_params.bcast_sta_id;
else
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
addr)) {
index = i;
break;
}
if (!priv->stations[i].used &&
index == IWL_INVALID_STATION)
index = i;
}
/* These two conditions have the same outcome, but keep them separate
since they have different meanings */
if (unlikely(index == IWL_INVALID_STATION)) {
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
return index;
}
if (priv->stations[index].used &&
!compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
return index;
}
IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
station = &priv->stations[index];
station->used = 1;
priv->num_stations++;
/* Set up the REPLY_ADD_STA command to send to device */
memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
station->sta.mode = 0;
station->sta.sta.sta_id = index;
station->sta.station_flags = 0;
/* BCAST station and IBSS stations do not work in HT mode */
if (index != priv->hw_params.bcast_sta_id &&
priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
iwl_set_ht_add_station(priv, index, ht_info);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
/* Add station to device's station table */
iwl_send_add_sta(priv, &station->sta, flags);
return index;
}
EXPORT_SYMBOL(iwl_add_station_flags);
static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
{
unsigned long flags;
u8 sta_id;
DECLARE_MAC_BUF(mac);
sta_id = iwl_find_station(priv, addr);
if (sta_id != IWL_INVALID_STATION) {
IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
print_mac(mac, addr));
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
memset(&priv->stations[sta_id], 0,
sizeof(struct iwl_station_entry));
spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
return -EINVAL;
}
static int iwl_remove_sta_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb)
{
struct iwl_rx_packet *res = NULL;
const char *addr = cmd->cmd.rm_sta.addr;
if (!skb) {
IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
return 1;
}
res = (struct iwl_rx_packet *)skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
return 1;
}
switch (res->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
break;
default:
break;
}
/* We didn't cache the SKB; let the caller free it */
return 1;
}
static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
u8 flags)
{
struct iwl_rx_packet *res = NULL;
int ret;
struct iwl_rem_sta_cmd rm_sta_cmd;
struct iwl_host_cmd cmd = {
.id = REPLY_REMOVE_STA,
.len = sizeof(struct iwl_rem_sta_cmd),
.meta.flags = flags,
.data = &rm_sta_cmd,
};
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
rm_sta_cmd.num_sta = 1;
memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
if (flags & CMD_ASYNC)
cmd.meta.u.callback = iwl_remove_sta_callback;
else
cmd.meta.flags |= CMD_WANT_SKB;
ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC))
return ret;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
res->hdr.flags);
ret = -EIO;
}
if (!ret) {
switch (res->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
iwl_sta_ucode_deactivate(priv, addr);
IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n");
break;
default:
ret = -EIO;
IWL_ERROR("REPLY_REMOVE_STA failed\n");
break;
}
}
priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb);
return ret;
}
/**
* iwl_remove_station - Remove driver's knowledge of station.
*
*/
u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
int index = IWL_INVALID_STATION;
int i;
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
if (is_ap)
index = IWL_AP_ID;
else if (is_broadcast_ether_addr(addr))
index = priv->hw_params.bcast_sta_id;
else
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
if (priv->stations[i].used &&
!compare_ether_addr(priv->stations[i].sta.sta.addr,
addr)) {
index = i;
break;
}
if (unlikely(index == IWL_INVALID_STATION))
goto out;
if (priv->stations[index].used) {
priv->stations[index].used = 0;
priv->num_stations--;
}
BUG_ON(priv->num_stations < 0);
spin_unlock_irqrestore(&priv->sta_lock, flags);
iwl_send_remove_station(priv, addr, CMD_ASYNC);
return index;
out:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
EXPORT_SYMBOL(iwl_remove_station);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv) int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{ {
int i; int i;
@ -200,7 +509,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
unsigned long flags; unsigned long flags;
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx; keyconf->hw_key_idx = HW_KEY_DEFAULT;
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
@ -230,7 +539,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
int ret; int ret;
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx;
key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@ -287,7 +595,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
key_flags |= STA_KEY_MULTICAST_MSK; key_flags |= STA_KEY_MULTICAST_MSK;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->hw_key_idx = keyconf->keyidx;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg; priv->stations[sta_id].keyinfo.alg = keyconf->alg;
@ -325,12 +632,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
keyconf->hw_key_idx = keyconf->keyidx;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg; priv->stations[sta_id].keyinfo.alg = keyconf->alg;
priv->stations[sta_id].keyinfo.conf = keyconf;
priv->stations[sta_id].keyinfo.keylen = 16; priv->stations[sta_id].keyinfo.keylen = 16;
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
@ -359,7 +664,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
u16 key_flags; u16 key_flags;
u8 keyidx; u8 keyidx;
priv->key_mapping_key = 0; priv->key_mapping_key--;
spin_lock_irqsave(&priv->sta_lock, flags); spin_lock_irqsave(&priv->sta_lock, flags);
key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
@ -390,31 +695,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_remove_dynamic_key); EXPORT_SYMBOL(iwl_remove_dynamic_key);
int iwl_set_dynamic_key(struct iwl_priv *priv, int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id) struct ieee80211_key_conf *keyconf, u8 sta_id)
{ {
int ret; int ret;
priv->key_mapping_key = 1; priv->key_mapping_key++;
keyconf->hw_key_idx = HW_KEY_DYNAMIC;
switch (key->alg) { switch (keyconf->alg) {
case ALG_CCMP: case ALG_CCMP:
ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
break; break;
case ALG_TKIP: case ALG_TKIP:
ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
break; break;
case ALG_WEP: case ALG_WEP:
ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
break; break;
default: default:
IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
ret = -EINVAL; ret = -EINVAL;
} }
@ -470,3 +776,168 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
} }
EXPORT_SYMBOL(iwl_send_lq_cmd); EXPORT_SYMBOL(iwl_send_lq_cmd);
/**
* iwl_sta_init_lq - Initialize a station's hardware rate table
*
* The uCode's station table contains a table of fallback rates
* for automatic fallback during transmission.
*
* NOTE: This sets up a default set of values. These will be replaced later
* if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
* rc80211_simple.
*
* NOTE: Run REPLY_ADD_STA command to set up station table entry, before
* calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
* which requires station table entry to exist).
*/
static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
int i, r;
struct iwl_link_quality_cmd link_cmd = {
.reserved1 = 0,
};
u16 rate_flags;
/* Set up the rate scaling to start at selected rate, fall back
* all the way down to 1M in IEEE order, and then spin on 1M */
if (is_ap)
r = IWL_RATE_54M_INDEX;
else if (priv->band == IEEE80211_BAND_5GHZ)
r = IWL_RATE_6M_INDEX;
else
r = IWL_RATE_1M_INDEX;
for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
rate_flags = 0;
if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
rate_flags |= RATE_MCS_CCK_MSK;
/* Use Tx antenna B only */
rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
link_cmd.rs_table[i].rate_n_flags =
iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
r = iwl4965_get_prev_ieee_rate(r);
}
link_cmd.general_params.single_stream_ant_msk = 2;
link_cmd.general_params.dual_stream_ant_msk = 3;
link_cmd.agg_params.agg_dis_start_th = 3;
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
/* Update the rate scaling for control frame Tx to AP */
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
sizeof(link_cmd), &link_cmd, NULL);
}
/**
* iwl_rxon_add_station - add station into station table.
*
* there is only one AP station with id= IWL_AP_ID
* NOTE: mutex must be held before calling this fnction
*/
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
u8 sta_id;
/* Add station to device's station table */
#ifdef CONFIG_IWL4965_HT
struct ieee80211_conf *conf = &priv->hw->conf;
struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
if ((is_ap) &&
(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
(priv->iw_mode == IEEE80211_IF_TYPE_STA))
sta_id = iwl_add_station_flags(priv, addr, is_ap,
0, cur_ht_config);
else
#endif /* CONFIG_IWL4965_HT */
sta_id = iwl_add_station_flags(priv, addr, is_ap,
0, NULL);
/* Set up default rate scaling table in device's station table */
iwl_sta_init_lq(priv, addr, is_ap);
return sta_id;
}
EXPORT_SYMBOL(iwl_rxon_add_station);
/**
* iwl_get_sta_id - Find station's index within station table
*
* If new IBSS station, create new entry in station table
*/
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
u16 fc = le16_to_cpu(hdr->frame_control);
DECLARE_MAC_BUF(mac);
/* If this frame is broadcast or management, use broadcast station id */
if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
/* If we are a client station in a BSS network, use the special
* AP station entry (that's the only station we communicate with) */
case IEEE80211_IF_TYPE_STA:
return IWL_AP_ID;
/* If we are an AP, then find the station, or use BCAST */
case IEEE80211_IF_TYPE_AP:
sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
return priv->hw_params.bcast_sta_id;
/* If this frame is going out to an IBSS network, find the station,
* or create a new station table entry */
case IEEE80211_IF_TYPE_IBSS:
sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
/* Create new station table entry */
sta_id = iwl_add_station_flags(priv, hdr->addr1,
0, CMD_ASYNC, NULL);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
IWL_DEBUG_DROP("Station %s not in station map. "
"Defaulting to broadcast...\n",
print_mac(mac, hdr->addr1));
iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
default:
IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
return priv->hw_params.bcast_sta_id;
}
}
EXPORT_SYMBOL(iwl_get_sta_id);
/**
* iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
*/
void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
{
unsigned long flags;
/* Remove "disable" flag, to enable Tx for this TID */
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags);
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);

View File

@ -29,6 +29,9 @@
#ifndef __iwl_sta_h__ #ifndef __iwl_sta_h__
#define __iwl_sta_h__ #define __iwl_sta_h__
#define HW_KEY_DYNAMIC 0
#define HW_KEY_DEFAULT 1
int iwl_get_free_ucode_key_index(struct iwl_priv *priv); int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
int iwl_remove_default_wep_key(struct iwl_priv *priv, int iwl_remove_default_wep_key(struct iwl_priv *priv,
@ -39,4 +42,8 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id); struct ieee80211_key_conf *key, u8 sta_id);
int iwl_remove_dynamic_key(struct iwl_priv *priv, int iwl_remove_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id); struct ieee80211_key_conf *key, u8 sta_id);
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
#endif /* __iwl_sta_h__ */ #endif /* __iwl_sta_h__ */

File diff suppressed because it is too large Load Diff

View File

@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
{
u16 fc = le16_to_cpu(hdr->frame_control);
int hdr_len = ieee80211_get_hdrlen(fc);
if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
return NULL;
}
static const struct ieee80211_supported_band *iwl3945_get_band( static const struct ieee80211_supported_band *iwl3945_get_band(
struct iwl3945_priv *priv, enum ieee80211_band band) struct iwl3945_priv *priv, enum ieee80211_band band)
{ {
@ -2386,13 +2376,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
} }
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
struct ieee80211_tx_control *ctl, struct ieee80211_tx_info *info,
struct iwl3945_cmd *cmd, struct iwl3945_cmd *cmd,
struct sk_buff *skb_frag, struct sk_buff *skb_frag,
int last_frag) int last_frag)
{ {
struct iwl3945_hw_key *keyinfo = struct iwl3945_hw_key *keyinfo =
&priv->stations[ctl->hw_key->hw_key_idx].keyinfo; &priv->stations[info->control.hw_key->hw_key_idx].keyinfo;
switch (keyinfo->alg) { switch (keyinfo->alg) {
case ALG_CCMP: case ALG_CCMP:
@ -2415,7 +2405,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
case ALG_WEP: case ALG_WEP:
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
(ctl->hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
if (keyinfo->keylen == 13) if (keyinfo->keylen == 13)
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
@ -2423,7 +2413,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX("Configuring packet for WEP encryption " IWL_DEBUG_TX("Configuring packet for WEP encryption "
"with key %d\n", ctl->hw_key->hw_key_idx); "with key %d\n", info->control.hw_key->hw_key_idx);
break; break;
default: default:
@ -2437,16 +2427,15 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
*/ */
static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd, struct iwl3945_cmd *cmd,
struct ieee80211_tx_control *ctrl, struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
int is_unicast, u8 std_id) int is_unicast, u8 std_id)
{ {
__le16 *qc;
u16 fc = le16_to_cpu(hdr->frame_control); u16 fc = le16_to_cpu(hdr->frame_control);
__le32 tx_flags = cmd->cmd.tx.tx_flags; __le32 tx_flags = cmd->cmd.tx.tx_flags;
cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK; tx_flags |= TX_CMD_FLG_ACK_MSK;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
@ -2462,17 +2451,18 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
if (ieee80211_get_morefrag(hdr)) if (ieee80211_get_morefrag(hdr))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
qc = ieee80211_get_qos_ctrl(hdr); if (ieee80211_is_qos_data(fc)) {
if (qc) { u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf); cmd->cmd.tx.tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
} else } else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_RTS_MSK;
tx_flags &= ~TX_CMD_FLG_CTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK;
} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_RTS_MSK;
tx_flags |= TX_CMD_FLG_CTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK;
} }
@ -2556,25 +2546,27 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
/* /*
* start REPLY_TX command process * start REPLY_TX command process
*/ */
static int iwl3945_tx_skb(struct iwl3945_priv *priv, static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl3945_tfd_frame *tfd; struct iwl3945_tfd_frame *tfd;
u32 *control_flags; u32 *control_flags;
int txq_id = ctl->queue; int txq_id = skb_get_queue_mapping(skb);
struct iwl3945_tx_queue *txq = NULL; struct iwl3945_tx_queue *txq = NULL;
struct iwl3945_queue *q = NULL; struct iwl3945_queue *q = NULL;
dma_addr_t phys_addr; dma_addr_t phys_addr;
dma_addr_t txcmd_phys; dma_addr_t txcmd_phys;
struct iwl3945_cmd *out_cmd = NULL; struct iwl3945_cmd *out_cmd = NULL;
u16 len, idx, len_org; u16 len, idx, len_org, hdr_len;
u8 id, hdr_len, unicast; u8 id;
u8 unicast;
u8 sta_id; u8 sta_id;
u8 tid = 0;
u16 seq_number = 0; u16 seq_number = 0;
u16 fc; u16 fc;
__le16 *qc;
u8 wait_write_ptr = 0; u8 wait_write_ptr = 0;
u8 *qc = NULL;
unsigned long flags; unsigned long flags;
int rc; int rc;
@ -2589,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
goto drop_unlock; goto drop_unlock;
} }
if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) {
IWL_ERROR("ERROR: No TX rate available.\n"); IWL_ERROR("ERROR: No TX rate available.\n");
goto drop_unlock; goto drop_unlock;
} }
@ -2632,9 +2624,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
IWL_DEBUG_RATE("station Id %d\n", sta_id); IWL_DEBUG_RATE("station Id %d\n", sta_id);
qc = ieee80211_get_qos_ctrl(hdr); if (ieee80211_is_qos_data(fc)) {
if (qc) { qc = ieee80211_get_qos_ctrl(hdr, hdr_len);
u8 tid = (u8)(le16_to_cpu(*qc) & 0xf); tid = qc[0] & 0xf;
seq_number = priv->stations[sta_id].tid[tid].seq_number & seq_number = priv->stations[sta_id].tid[tid].seq_number &
IEEE80211_SCTL_SEQ; IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = cpu_to_le16(seq_number) | hdr->seq_ctrl = cpu_to_le16(seq_number) |
@ -2658,8 +2650,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
/* Set up driver data for this TFD */ /* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
txq->txb[q->write_ptr].skb[0] = skb; txq->txb[q->write_ptr].skb[0] = skb;
memcpy(&(txq->txb[q->write_ptr].status.control),
ctl, sizeof(struct ieee80211_tx_control));
/* Init first empty entry in queue's array of Tx/cmd buffers */ /* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = &txq->cmd[idx]; out_cmd = &txq->cmd[idx];
@ -2708,8 +2698,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
* first entry */ * first entry */
iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb, /* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */ * if any (802.11 null frames have no payload). */
@ -2734,10 +2724,10 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
out_cmd->cmd.tx.len = cpu_to_le16(len); out_cmd->cmd.tx.len = cpu_to_le16(len);
/* TODO need this for burst mode later on */ /* TODO need this for burst mode later on */
iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id);
/* set is_hcca to 0; it probably will never be implemented */ /* set is_hcca to 0; it probably will never be implemented */
iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@ -2745,7 +2735,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
if (!ieee80211_get_morefrag(hdr)) { if (!ieee80211_get_morefrag(hdr)) {
txq->need_update = 1; txq->need_update = 1;
if (qc) { if (qc) {
u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
priv->stations[sta_id].tid[tid].seq_number = seq_number; priv->stations[sta_id].tid[tid].seq_number = seq_number;
} }
} else { } else {
@ -2776,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
ieee80211_stop_queue(priv->hw, ctl->queue); ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
} }
return 0; return 0;
@ -3239,7 +3228,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
struct sk_buff *beacon; struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!beacon) { if (!beacon) {
IWL_ERROR("update beacon failed\n"); IWL_ERROR("update beacon failed\n");
@ -5832,7 +5821,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
if (iwl3945_is_rfkill(priv)) if (iwl3945_is_rfkill(priv))
return; return;
ieee80211_start_queues(priv->hw); ieee80211_wake_queues(priv->hw);
priv->active_rate = priv->rates_mask; priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@ -5858,9 +5847,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
/* Configure the adapter for unassociated operation */ /* Configure the adapter for unassociated operation */
iwl3945_commit_rxon(priv); iwl3945_commit_rxon(priv);
/* At this point, the NIC is initialized and operational */
priv->notif_missed_beacons = 0;
iwl3945_reg_txpower_periodic(priv); iwl3945_reg_txpower_periodic(priv);
iwl3945_led_register(priv); iwl3945_led_register(priv);
@ -6690,8 +6676,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211("leave\n"); IWL_DEBUG_MAC80211("leave\n");
} }
static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct iwl3945_priv *priv = hw->priv; struct iwl3945_priv *priv = hw->priv;
@ -6703,9 +6688,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
} }
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ctl->tx_rate->bitrate); ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
if (iwl3945_tx_skb(priv, skb, ctl)) if (iwl3945_tx_skb(priv, skb))
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
IWL_DEBUG_MAC80211("leave\n"); IWL_DEBUG_MAC80211("leave\n");
@ -7342,8 +7327,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
} }
static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct iwl3945_priv *priv = hw->priv; struct iwl3945_priv *priv = hw->priv;
unsigned long flags; unsigned long flags;
@ -8273,7 +8257,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_free_channel_map(priv); iwl3945_free_channel_map(priv);
iwl3945_free_geos(priv); iwl3945_free_geos(priv);
kfree(priv->scan);
if (priv->ibss_beacon) if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon); dev_kfree_skb(priv->ibss_beacon);

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,5 @@
libertas-objs := main.o wext.o \ libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
rx.o tx.o cmd.o \ debugfs.o persistcfg.o ethtool.o assoc.o
cmdresp.o scan.o \
11d.o \
debugfs.o \
ethtool.o assoc.o
usb8xxx-objs += if_usb.o usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o libertas_cs-objs += if_cs.o

View File

@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
/* Change mesh channel first; 21.p21 firmware won't let /* Change mesh channel first; 21.p21 firmware won't let
you change channel otherwise (even though it'll return you change channel otherwise (even though it'll return
an error to this */ an error to this */
lbs_mesh_config(priv, 0, assoc_req->channel); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
assoc_req->channel);
} }
lbs_deb_assoc("ASSOC: channel: %d -> %d\n", lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh: restore_mesh:
if (priv->mesh_dev) if (priv->mesh_dev)
lbs_mesh_config(priv, 1, priv->curbssparams.channel); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel);
done: done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@ -1248,7 +1250,7 @@ static int get_common_rates(struct lbs_private *priv,
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
if (!priv->auto_rate) { if (!priv->enablehwauto) {
for (i = 0; i < tmp_size; i++) { for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate) if (tmp[i] == priv->cur_rate)
goto done; goto done;

View File

@ -4,6 +4,7 @@
*/ */
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <net/ieee80211.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include "host.h" #include "host.h"
#include "hostcmd.h" #include "hostcmd.h"
@ -109,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
* CF card firmware 5.0.16p0: cap 0x00000303 * CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303
*/ */
printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n", lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
print_mac(mac, cmd.permanentaddr), print_mac(mac, cmd.permanentaddr),
priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 16 & 0xff,
@ -675,26 +676,60 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
return 0; return 0;
} }
static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
struct cmd_ds_command *cmd,
u16 cmd_action)
{ {
struct cmd_ds_802_11_rate_adapt_rateset /* Bit Rate
*rateadapt = &cmd->params.rateset; * 15:13 Reserved
* 12 54 Mbps
* 11 48 Mbps
* 10 36 Mbps
* 9 24 Mbps
* 8 18 Mbps
* 7 12 Mbps
* 6 9 Mbps
* 5 6 Mbps
* 4 Reserved
* 3 11 Mbps
* 2 5.5 Mbps
* 1 2 Mbps
* 0 1 Mbps
**/
uint16_t ratemask;
int i = lbs_data_rate_to_fw_index(rate);
if (lower_rates_ok)
ratemask = (0x1fef >> (12 - i));
else
ratemask = (1 << i);
return cpu_to_le16(ratemask);
}
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action)
{
struct cmd_ds_802_11_rate_adapt_rateset cmd;
int ret;
lbs_deb_enter(LBS_DEB_CMD); lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ S_DS_GEN);
cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
rateadapt->action = cpu_to_le16(cmd_action); if (!priv->cur_rate && !priv->enablehwauto)
rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto); return -EINVAL;
rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
lbs_deb_leave(LBS_DEB_CMD); cmd.hdr.size = cpu_to_le16(sizeof(cmd));
return 0;
cmd.action = cpu_to_le16(cmd_action);
cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
if (!ret && cmd_action == CMD_ACT_GET) {
priv->ratebitmap = le16_to_cpu(cmd.bitmap);
priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
}
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
} }
EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
/** /**
* @brief Set the data rate * @brief Set the data rate
@ -746,28 +781,6 @@ out:
return ret; return ret;
} }
static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
struct cmd_ds_command *cmd,
u16 cmd_action)
{
struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
lbs_deb_enter(LBS_DEB_CMD);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
S_DS_GEN);
cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
pMCastAdr->action = cpu_to_le16(cmd_action);
pMCastAdr->nr_of_adrs =
cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
memcpy(pMCastAdr->maclist, priv->multicastlist,
priv->nr_of_multicastmacaddr * ETH_ALEN);
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
/** /**
* @brief Get the radio channel * @brief Get the radio channel
* *
@ -1020,24 +1033,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
return ret; return ret;
} }
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type)
{
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
cmd->hdr.result = 0;
cmd->type = cpu_to_le16(type);
cmd->action = cpu_to_le16(action);
ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
* START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
* lbs_mesh_config_send.
*/
int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
{ {
struct cmd_ds_mesh_config cmd; struct cmd_ds_mesh_config cmd;
struct mrvl_meshie *ie;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.action = cpu_to_le16(enable);
cmd.channel = cpu_to_le16(chan); cmd.channel = cpu_to_le16(chan);
cmd.type = cpu_to_le16(priv->mesh_tlv); ie = (struct mrvl_meshie *)cmd.data;
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (enable) { switch (action) {
cmd.length = cpu_to_le16(priv->mesh_ssid_len); case CMD_ACT_MESH_CONFIG_START:
memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); ie->hdr.id = MFIE_TYPE_GENERIC;
ie->val.oui[0] = 0x00;
ie->val.oui[1] = 0x50;
ie->val.oui[2] = 0x43;
ie->val.type = MARVELL_MESH_IE_TYPE;
ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
ie->val.version = MARVELL_MESH_IE_VERSION;
ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->hdr.len = sizeof(struct mrvl_meshie_val) -
IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
case CMD_ACT_MESH_CONFIG_STOP:
break;
default:
return -1;
} }
lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
enable, priv->mesh_tlv, chan, action, priv->mesh_tlv, chan,
escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
} }
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@ -1112,7 +1170,7 @@ static void lbs_submit_command(struct lbs_private *priv,
struct cmd_header *cmd; struct cmd_header *cmd;
uint16_t cmdsize; uint16_t cmdsize;
uint16_t command; uint16_t command;
int timeo = 5 * HZ; int timeo = 3 * HZ;
int ret; int ret;
lbs_deb_enter(LBS_DEB_HOST); lbs_deb_enter(LBS_DEB_HOST);
@ -1130,7 +1188,7 @@ static void lbs_submit_command(struct lbs_private *priv,
/* These commands take longer */ /* These commands take longer */
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
command == CMD_802_11_AUTHENTICATE) command == CMD_802_11_AUTHENTICATE)
timeo = 10 * HZ; timeo = 5 * HZ;
lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n", lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
command, le16_to_cpu(cmd->seqnum), cmdsize); command, le16_to_cpu(cmd->seqnum), cmdsize);
@ -1142,7 +1200,7 @@ static void lbs_submit_command(struct lbs_private *priv,
lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
/* Let the timer kick in and retry, and potentially reset /* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */ the whole thing if the condition persists */
timeo = HZ; timeo = HZ/4;
} }
/* Setup the timer after transmit command */ /* Setup the timer after transmit command */
@ -1247,8 +1305,7 @@ void lbs_set_mac_control(struct lbs_private *priv)
cmd.action = cpu_to_le16(priv->mac_control); cmd.action = cpu_to_le16(priv->mac_control);
cmd.reserved = 0; cmd.reserved = 0;
lbs_cmd_async(priv, CMD_MAC_CONTROL, lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
&cmd.hdr, sizeof(cmd));
lbs_deb_leave(LBS_DEB_CMD); lbs_deb_leave(LBS_DEB_CMD);
} }
@ -1355,15 +1412,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
cmd_action, pdata_buf); cmd_action, pdata_buf);
break; break;
case CMD_802_11_RATE_ADAPT_RATESET:
ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
cmdptr, cmd_action);
break;
case CMD_MAC_MULTICAST_ADR:
ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
break;
case CMD_802_11_MONITOR_MODE: case CMD_802_11_MONITOR_MODE:
ret = lbs_cmd_802_11_monitor_mode(cmdptr, ret = lbs_cmd_802_11_monitor_mode(cmdptr,
cmd_action, pdata_buf); cmd_action, pdata_buf);
@ -1452,7 +1500,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break; break;
default: default:
lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1; ret = -1;
break; break;
} }

View File

@ -39,12 +39,17 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv); int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel); int lbs_set_channel(struct lbs_private *priv, u8 channel);
int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
int lbs_suspend(struct lbs_private *priv); int lbs_suspend(struct lbs_private *priv);
void lbs_resume(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv);
int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
uint16_t cmd_action);
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
uint16_t cmd_action, uint16_t *timeout); uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,

View File

@ -203,22 +203,6 @@ static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
return 0; return 0;
} }
static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
lbs_deb_enter(LBS_DEB_CMD);
if (rates->action == CMD_ACT_GET) {
priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
priv->ratebitmap = le16_to_cpu(rates->bitmap);
}
lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int lbs_ret_802_11_rssi(struct lbs_private *priv, static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp) struct cmd_ds_command *resp)
{ {
@ -316,16 +300,11 @@ static inline int handle_cmd_response(struct lbs_private *priv,
break; break;
case CMD_RET(CMD_MAC_MULTICAST_ADR):
case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_RESET):
case CMD_RET(CMD_802_11_AUTHENTICATE): case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_BEACON_STOP): case CMD_RET(CMD_802_11_BEACON_STOP):
break; break;
case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
break;
case CMD_RET(CMD_802_11_RSSI): case CMD_RET(CMD_802_11_RSSI):
ret = lbs_ret_802_11_rssi(priv, resp); ret = lbs_ret_802_11_rssi(priv, resp);
break; break;
@ -376,8 +355,8 @@ static inline int handle_cmd_response(struct lbs_private *priv,
break; break;
default: default:
lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
le16_to_cpu(resp->command)); le16_to_cpu(resp->command));
break; break;
} }
lbs_deb_leave(LBS_DEB_HOST); lbs_deb_leave(LBS_DEB_HOST);

View File

@ -60,6 +60,10 @@ void lbs_mac_event_disconnected(struct lbs_private *priv);
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* persistcfg.c */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
/* main.c */ /* main.c */
struct chan_freq_power *lbs_get_region_cfp_table(u8 region, struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
int *cfp_no); int *cfp_no);

View File

@ -40,6 +40,7 @@
#define LBS_DEB_THREAD 0x00100000 #define LBS_DEB_THREAD 0x00100000
#define LBS_DEB_HEX 0x00200000 #define LBS_DEB_HEX 0x00200000
#define LBS_DEB_SDIO 0x00400000 #define LBS_DEB_SDIO 0x00400000
#define LBS_DEB_SYSFS 0x00800000
extern unsigned int lbs_debug; extern unsigned int lbs_debug;
@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) #define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args) #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_pr_info(format, args...) \ #define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args) printk(KERN_INFO DRV_NAME": " format, ## args)
@ -170,6 +172,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_IE_LENGTH 9 #define MARVELL_MESH_IE_LENGTH 9
/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
* is when enabling the mesh using CMD_MESH_CONFIG.
*/
#define MARVELL_MESH_IE_TYPE 4
#define MARVELL_MESH_IE_SUBTYPE 0
#define MARVELL_MESH_IE_VERSION 0
#define MARVELL_MESH_PROTO_ID_HWMP 0
#define MARVELL_MESH_METRIC_ID 0
#define MARVELL_MESH_CAPABILITY 0
/** INT status Bit Definition*/ /** INT status Bit Definition*/
#define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002 #define MRVDRV_RX_UPLD_RDY 0x0002

View File

@ -140,6 +140,8 @@ struct lbs_private {
wait_queue_head_t waitq; wait_queue_head_t waitq;
struct workqueue_struct *work_thread; struct workqueue_struct *work_thread;
struct work_struct mcast_work;
/** Scanning */ /** Scanning */
struct delayed_work scan_work; struct delayed_work scan_work;
struct delayed_work assoc_work; struct delayed_work assoc_work;
@ -151,6 +153,7 @@ struct lbs_private {
/** Hardware access */ /** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
/* Wake On LAN */ /* Wake On LAN */
uint32_t wol_criteria; uint32_t wol_criteria;
@ -234,8 +237,8 @@ struct lbs_private {
/** 802.11 statistics */ /** 802.11 statistics */
// struct cmd_DS_802_11_GET_STAT wlan802_11Stat; // struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
u16 enablehwauto; uint16_t enablehwauto;
u16 ratebitmap; uint16_t ratebitmap;
u32 fragthsd; u32 fragthsd;
u32 rtsthsd; u32 rtsthsd;
@ -293,7 +296,6 @@ struct lbs_private {
/** data rate stuff */ /** data rate stuff */
u8 cur_rate; u8 cur_rate;
u8 auto_rate;
/** RF calibration data */ /** RF calibration data */

View File

@ -256,6 +256,23 @@ enum cmd_mesh_access_opts {
CMD_ACT_MESH_GET_AUTOSTART_ENABLED, CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
}; };
/* Define actions and types for CMD_MESH_CONFIG */
enum cmd_mesh_config_actions {
CMD_ACT_MESH_CONFIG_STOP = 0,
CMD_ACT_MESH_CONFIG_START,
CMD_ACT_MESH_CONFIG_SET,
CMD_ACT_MESH_CONFIG_GET,
};
enum cmd_mesh_config_types {
CMD_TYPE_MESH_SET_BOOTFLAG = 1,
CMD_TYPE_MESH_SET_BOOTTIME,
CMD_TYPE_MESH_SET_DEF_CHANNEL,
CMD_TYPE_MESH_SET_MESH_IE,
CMD_TYPE_MESH_GET_DEFAULTS,
CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
};
/** Card Event definition */ /** Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1 #define MACREG_INT_CODE_TX_DMA_DONE 1

View File

@ -219,6 +219,7 @@ struct cmd_ds_mac_control {
}; };
struct cmd_ds_mac_multicast_adr { struct cmd_ds_mac_multicast_adr {
struct cmd_header hdr;
__le16 action; __le16 action;
__le16 nr_of_adrs; __le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
@ -499,6 +500,7 @@ struct cmd_ds_802_11_data_rate {
}; };
struct cmd_ds_802_11_rate_adapt_rateset { struct cmd_ds_802_11_rate_adapt_rateset {
struct cmd_header hdr;
__le16 action; __le16 action;
__le16 enablehwauto; __le16 enablehwauto;
__le16 bitmap; __le16 bitmap;
@ -702,8 +704,6 @@ struct cmd_ds_command {
struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_rate_adapt_rateset rateset;
struct cmd_ds_mac_multicast_adr madr;
struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_ad_hoc_join adj;
struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_802_11_rssi_rsp rssirsp;

View File

@ -148,76 +148,72 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
{ {
int i; int i;
for (i = 0; i < 1000; i++) { for (i = 0; i < 100000; i++) {
u8 val = if_cs_read8(card, addr); u8 val = if_cs_read8(card, addr);
if (val == reg) if (val == reg)
return i; return i;
udelay(500); udelay(5);
} }
return -ETIME; return -ETIME;
} }
/* Host control registers and their bit definitions */ /* First the bitmasks for the host/card interrupt/status registers: */
#define IF_CS_BIT_TX 0x0001
#define IF_CS_BIT_RX 0x0002
#define IF_CS_BIT_COMMAND 0x0004
#define IF_CS_BIT_RESP 0x0008
#define IF_CS_BIT_EVENT 0x0010
#define IF_CS_BIT_MASK 0x001f
#define IF_CS_H_STATUS 0x00000000 /* And now the individual registers and assorted masks */
#define IF_CS_H_STATUS_TX_OVER 0x0001 #define IF_CS_HOST_STATUS 0x00000000
#define IF_CS_H_STATUS_RX_OVER 0x0002
#define IF_CS_H_STATUS_DNLD_OVER 0x0004
#define IF_CS_H_INT_CAUSE 0x00000002 #define IF_CS_HOST_INT_CAUSE 0x00000002
#define IF_CS_H_IC_TX_OVER 0x0001
#define IF_CS_H_IC_RX_OVER 0x0002
#define IF_CS_H_IC_DNLD_OVER 0x0004
#define IF_CS_H_IC_POWER_DOWN 0x0008
#define IF_CS_H_IC_HOST_EVENT 0x0010
#define IF_CS_H_IC_MASK 0x001f
#define IF_CS_H_INT_MASK 0x00000004 #define IF_CS_HOST_INT_MASK 0x00000004
#define IF_CS_H_IM_MASK 0x001f
#define IF_CS_H_WRITE_LEN 0x00000014 #define IF_CS_HOST_WRITE 0x00000016
#define IF_CS_HOST_WRITE_LEN 0x00000014
#define IF_CS_H_WRITE 0x00000016 #define IF_CS_HOST_CMD 0x0000001A
#define IF_CS_HOST_CMD_LEN 0x00000018
#define IF_CS_H_CMD_LEN 0x00000018 #define IF_CS_READ 0x00000010
#define IF_CS_READ_LEN 0x00000024
#define IF_CS_H_CMD 0x0000001A #define IF_CS_CARD_CMD 0x00000012
#define IF_CS_CARD_CMD_LEN 0x00000030
#define IF_CS_C_READ_LEN 0x00000024 #define IF_CS_CARD_STATUS 0x00000020
#define IF_CS_CARD_STATUS_MASK 0x7f00
#define IF_CS_H_READ 0x00000010 #define IF_CS_CARD_INT_CAUSE 0x00000022
/* Card control registers and their bit definitions */ #define IF_CS_CARD_SQ_READ_LOW 0x00000028
#define IF_CS_CARD_SQ_HELPER_OK 0x10
#define IF_CS_C_STATUS 0x00000020
#define IF_CS_C_S_TX_DNLD_RDY 0x0001
#define IF_CS_C_S_RX_UPLD_RDY 0x0002
#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
#define IF_CS_C_S_CARDEVENT 0x0010
#define IF_CS_C_S_MASK 0x001f
#define IF_CS_C_S_STATUS_MASK 0x7f00
#define IF_CS_C_INT_CAUSE 0x00000022
#define IF_CS_C_IC_MASK 0x001f
#define IF_CS_C_SQ_READ_LOW 0x00000028
#define IF_CS_C_SQ_HELPER_OK 0x10
#define IF_CS_C_CMD_LEN 0x00000030
#define IF_CS_C_CMD 0x00000012
#define IF_CS_SCRATCH 0x0000003F #define IF_CS_SCRATCH 0x0000003F
/********************************************************************/ /********************************************************************/
/* I/O */ /* I/O and interrupt handling */
/********************************************************************/ /********************************************************************/
static inline void if_cs_enable_ints(struct if_cs_card *card)
{
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
}
static inline void if_cs_disable_ints(struct if_cs_card *card)
{
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
}
/* /*
* Called from if_cs_host_to_card to send a command to the hardware * Called from if_cs_host_to_card to send a command to the hardware
*/ */
@ -228,11 +224,12 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
int loops = 0; int loops = 0;
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
if_cs_disable_ints(card);
/* Is hardware ready? */ /* Is hardware ready? */
while (1) { while (1) {
u16 val = if_cs_read16(card, IF_CS_C_STATUS); u16 val = if_cs_read16(card, IF_CS_CARD_STATUS);
if (val & IF_CS_C_S_CMD_DNLD_RDY) if (val & IF_CS_BIT_COMMAND)
break; break;
if (++loops > 100) { if (++loops > 100) {
lbs_pr_err("card not ready for commands\n"); lbs_pr_err("card not ready for commands\n");
@ -241,51 +238,56 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
mdelay(1); mdelay(1);
} }
if_cs_write16(card, IF_CS_H_CMD_LEN, nb); if_cs_write16(card, IF_CS_HOST_CMD_LEN, nb);
if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); if_cs_write16_rep(card, IF_CS_HOST_CMD, buf, nb / 2);
/* Are we supposed to transfer an odd amount of bytes? */ /* Are we supposed to transfer an odd amount of bytes? */
if (nb & 1) if (nb & 1)
if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); if_cs_write8(card, IF_CS_HOST_CMD, buf[nb-1]);
/* "Assert the download over interrupt command in the Host /* "Assert the download over interrupt command in the Host
* status register" */ * status register" */
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
/* "Assert the download over interrupt command in the Card /* "Assert the download over interrupt command in the Card
* interrupt case register" */ * interrupt case register" */
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
ret = 0; ret = 0;
done: done:
if_cs_enable_ints(card);
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret; return ret;
} }
/* /*
* Called from if_cs_host_to_card to send a data to the hardware * Called from if_cs_host_to_card to send a data to the hardware
*/ */
static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
{ {
struct if_cs_card *card = (struct if_cs_card *)priv->card; struct if_cs_card *card = (struct if_cs_card *)priv->card;
u16 status;
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
if_cs_disable_ints(card);
if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); status = if_cs_read16(card, IF_CS_CARD_STATUS);
BUG_ON((status & IF_CS_BIT_TX) == 0);
if_cs_write16(card, IF_CS_HOST_WRITE_LEN, nb);
/* write even number of bytes, then odd byte if necessary */ /* write even number of bytes, then odd byte if necessary */
if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); if_cs_write16_rep(card, IF_CS_HOST_WRITE, buf, nb / 2);
if (nb & 1) if (nb & 1)
if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); if_cs_write8(card, IF_CS_HOST_WRITE, buf[nb-1]);
if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
if_cs_enable_ints(card);
lbs_deb_leave(LBS_DEB_CS); lbs_deb_leave(LBS_DEB_CS);
} }
/* /*
* Get the command result out of the card. * Get the command result out of the card.
*/ */
@ -293,27 +295,28 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
{ {
unsigned long flags; unsigned long flags;
int ret = -1; int ret = -1;
u16 val; u16 status;
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
/* is hardware ready? */ /* is hardware ready? */
val = if_cs_read16(priv->card, IF_CS_C_STATUS); status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { if ((status & IF_CS_BIT_RESP) == 0) {
lbs_pr_err("card not ready for CMD\n"); lbs_pr_err("no cmd response in card\n");
*len = 0;
goto out; goto out;
} }
*len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); *len = if_cs_read16(priv->card, IF_CS_CARD_CMD_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
goto out; goto out;
} }
/* read even number of bytes, then odd byte if necessary */ /* read even number of bytes, then odd byte if necessary */
if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); if_cs_read16_rep(priv->card, IF_CS_CARD_CMD, data, *len/sizeof(u16));
if (*len & 1) if (*len & 1)
data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); data[*len-1] = if_cs_read8(priv->card, IF_CS_CARD_CMD);
/* This is a workaround for a firmware that reports too much /* This is a workaround for a firmware that reports too much
* bytes */ * bytes */
@ -330,7 +333,6 @@ out:
return ret; return ret;
} }
static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
@ -339,7 +341,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); len = if_cs_read16(priv->card, IF_CS_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
priv->stats.rx_dropped++; priv->stats.rx_dropped++;
@ -354,38 +356,19 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
data = skb->data; data = skb->data;
/* read even number of bytes, then odd byte if necessary */ /* read even number of bytes, then odd byte if necessary */
if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
if (len & 1) if (len & 1)
data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
dat_err: dat_err:
if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
out: out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
return skb; return skb;
} }
/********************************************************************/
/* Interrupts */
/********************************************************************/
static inline void if_cs_enable_ints(struct if_cs_card *card)
{
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_H_INT_MASK, 0);
}
static inline void if_cs_disable_ints(struct if_cs_card *card)
{
lbs_deb_enter(LBS_DEB_CS);
if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
}
static irqreturn_t if_cs_interrupt(int irq, void *data) static irqreturn_t if_cs_interrupt(int irq, void *data)
{ {
struct if_cs_card *card = data; struct if_cs_card *card = data;
@ -394,10 +377,8 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
lbs_deb_enter(LBS_DEB_CS); lbs_deb_enter(LBS_DEB_CS);
cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); /* Ask card interrupt cause register if there is something for us */
if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
lbs_deb_cs("cause 0x%04x\n", cause);
if (cause == 0) { if (cause == 0) {
/* Not for us */ /* Not for us */
return IRQ_NONE; return IRQ_NONE;
@ -409,11 +390,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* TODO: I'm not sure what the best ordering is */ /* Clear interrupt cause */
if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
lbs_deb_cs("cause 0x%04x\n", cause);
cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; if (cause & IF_CS_BIT_RX) {
if (cause & IF_CS_C_S_RX_UPLD_RDY) {
struct sk_buff *skb; struct sk_buff *skb;
lbs_deb_cs("rx packet\n"); lbs_deb_cs("rx packet\n");
skb = if_cs_receive_data(priv); skb = if_cs_receive_data(priv);
@ -421,16 +402,16 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
lbs_process_rxed_packet(priv, skb); lbs_process_rxed_packet(priv, skb);
} }
if (cause & IF_CS_H_IC_TX_OVER) { if (cause & IF_CS_BIT_TX) {
lbs_deb_cs("tx over\n"); lbs_deb_cs("tx done\n");
lbs_host_to_card_done(priv); lbs_host_to_card_done(priv);
} }
if (cause & IF_CS_C_S_CMD_UPLD_RDY) { if (cause & IF_CS_BIT_RESP) {
unsigned long flags; unsigned long flags;
u8 i; u8 i;
lbs_deb_cs("cmd upload ready\n"); lbs_deb_cs("cmd resp\n");
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
i = (priv->resp_idx == 0) ? 1 : 0; i = (priv->resp_idx == 0) ? 1 : 0;
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
@ -444,15 +425,16 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
spin_unlock_irqrestore(&priv->driver_lock, flags); spin_unlock_irqrestore(&priv->driver_lock, flags);
} }
if (cause & IF_CS_H_IC_HOST_EVENT) { if (cause & IF_CS_BIT_EVENT) {
u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS) u16 event = if_cs_read16(priv->card, IF_CS_CARD_STATUS)
& IF_CS_C_S_STATUS_MASK; & IF_CS_CARD_STATUS_MASK;
if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
IF_CS_H_IC_HOST_EVENT); IF_CS_BIT_EVENT);
lbs_deb_cs("eventcause 0x%04x\n", event); lbs_deb_cs("host event 0x%04x\n", event);
lbs_queue_event(priv, event >> 8 & 0xff); lbs_queue_event(priv, event >> 8 & 0xff);
} }
lbs_deb_leave(LBS_DEB_CS);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -514,26 +496,26 @@ static int if_cs_prog_helper(struct if_cs_card *card)
/* "write the number of bytes to be sent to the I/O Command /* "write the number of bytes to be sent to the I/O Command
* write length register" */ * write length register" */
if_cs_write16(card, IF_CS_H_CMD_LEN, count); if_cs_write16(card, IF_CS_HOST_CMD_LEN, count);
/* "write this to I/O Command port register as 16 bit writes */ /* "write this to I/O Command port register as 16 bit writes */
if (count) if (count)
if_cs_write16_rep(card, IF_CS_H_CMD, if_cs_write16_rep(card, IF_CS_HOST_CMD,
&fw->data[sent], &fw->data[sent],
count >> 1); count >> 1);
/* "Assert the download over interrupt command in the Host /* "Assert the download over interrupt command in the Host
* status register" */ * status register" */
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
/* "Assert the download over interrupt command in the Card /* "Assert the download over interrupt command in the Card
* interrupt case register" */ * interrupt case register" */
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
/* "The host polls the Card Status register ... for 50 ms before /* "The host polls the Card Status register ... for 50 ms before
declaring a failure */ declaring a failure */
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_C_S_CMD_DNLD_RDY); IF_CS_BIT_COMMAND);
if (ret < 0) { if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n", lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret); sent, ret);
@ -575,14 +557,15 @@ static int if_cs_prog_real(struct if_cs_card *card)
} }
lbs_deb_cs("fw size %td\n", fw->size); lbs_deb_cs("fw size %td\n", fw->size);
ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_SQ_READ_LOW,
IF_CS_CARD_SQ_HELPER_OK);
if (ret < 0) { if (ret < 0) {
lbs_pr_err("helper firmware doesn't answer\n"); lbs_pr_err("helper firmware doesn't answer\n");
goto err_release; goto err_release;
} }
for (sent = 0; sent < fw->size; sent += len) { for (sent = 0; sent < fw->size; sent += len) {
len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); len = if_cs_read16(card, IF_CS_CARD_SQ_READ_LOW);
if (len & 1) { if (len & 1) {
retry++; retry++;
lbs_pr_info("odd, need to retry this firmware block\n"); lbs_pr_info("odd, need to retry this firmware block\n");
@ -600,16 +583,16 @@ static int if_cs_prog_real(struct if_cs_card *card)
} }
if_cs_write16(card, IF_CS_H_CMD_LEN, len); if_cs_write16(card, IF_CS_HOST_CMD_LEN, len);
if_cs_write16_rep(card, IF_CS_H_CMD, if_cs_write16_rep(card, IF_CS_HOST_CMD,
&fw->data[sent], &fw->data[sent],
(len+1) >> 1); (len+1) >> 1);
if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_C_S_CMD_DNLD_RDY); IF_CS_BIT_COMMAND);
if (ret < 0) { if (ret < 0) {
lbs_pr_err("can't download firmware at 0x%x\n", sent); lbs_pr_err("can't download firmware at 0x%x\n", sent);
goto err_release; goto err_release;
@ -837,7 +820,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/* Clear any interrupt cause that happend while sending /* Clear any interrupt cause that happend while sending
* firmware/initializing card */ * firmware/initializing card */
if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK); if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
if_cs_enable_ints(card); if_cs_enable_ints(card);
/* And finally bring the card up */ /* And finally bring the card up */

View File

@ -7,6 +7,10 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#ifdef CONFIG_OLPC
#include <asm/olpc.h>
#endif
#define DRV_NAME "usb8xxx" #define DRV_NAME "usb8xxx"
#include "host.h" #include "host.h"
@ -146,6 +150,14 @@ static void if_usb_fw_timeo(unsigned long priv)
wake_up(&cardp->fw_wq); wake_up(&cardp->fw_wq);
} }
#ifdef CONFIG_OLPC
static void if_usb_reset_olpc_card(struct lbs_private *priv)
{
printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
}
#endif
/** /**
* @brief sets the configuration values * @brief sets the configuration values
* @param ifnum interface number * @param ifnum interface number
@ -231,6 +243,11 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1; cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card; priv->hw_host_to_card = if_usb_host_to_card;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
#endif
cardp->boot2_version = udev->descriptor.bcdDevice; cardp->boot2_version = udev->descriptor.bcdDevice;
if_usb_submit_rx_urb(cardp); if_usb_submit_rx_urb(cardp);
@ -364,6 +381,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
ret = usb_reset_device(cardp->udev); ret = usb_reset_device(cardp->udev);
msleep(100); msleep(100);
#ifdef CONFIG_OLPC
if (ret && machine_is_olpc())
if_usb_reset_olpc_card(NULL);
#endif
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret; return ret;

View File

@ -11,6 +11,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/stddef.h>
#include <net/iw_handler.h> #include <net/iw_handler.h>
#include <net/ieee80211.h> #include <net/ieee80211.h>
@ -343,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev,
{ {
struct lbs_private *priv = to_net_dev(dev)->priv; struct lbs_private *priv = to_net_dev(dev)->priv;
int enable; int enable;
int ret; int ret, action = CMD_ACT_MESH_CONFIG_STOP;
sscanf(buf, "%x", &enable); sscanf(buf, "%x", &enable);
enable = !!enable; enable = !!enable;
if (enable == !!priv->mesh_dev) if (enable == !!priv->mesh_dev)
return count; return count;
if (enable)
ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); action = CMD_ACT_MESH_CONFIG_START;
ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
if (ret) if (ret)
return ret; return ret;
@ -446,6 +448,8 @@ static int lbs_mesh_stop(struct net_device *dev)
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
schedule_work(&priv->mcast_work);
lbs_deb_leave(LBS_DEB_MESH); lbs_deb_leave(LBS_DEB_MESH);
return 0; return 0;
} }
@ -467,6 +471,8 @@ static int lbs_eth_stop(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock); spin_unlock_irq(&priv->driver_lock);
schedule_work(&priv->mcast_work);
lbs_deb_leave(LBS_DEB_NET); lbs_deb_leave(LBS_DEB_NET);
return 0; return 0;
} }
@ -563,87 +569,114 @@ done:
return ret; return ret;
} }
static int lbs_copy_multicast_address(struct lbs_private *priv,
struct net_device *dev)
{
int i = 0;
struct dev_mc_list *mcptr = dev->mc_list;
for (i = 0; i < dev->mc_count; i++) { static inline int mac_in_list(unsigned char *list, int list_len,
memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); unsigned char *mac)
mcptr = mcptr->next; {
while (list_len) {
if (!memcmp(list, mac, ETH_ALEN))
return 1;
list += ETH_ALEN;
list_len--;
} }
return 0;
}
static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
struct net_device *dev, int nr_addrs)
{
int i = nr_addrs;
struct dev_mc_list *mc_list;
DECLARE_MAC_BUF(mac);
if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
return nr_addrs;
netif_tx_lock_bh(dev);
for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
print_mac(mac, mc_list->dmi_addr));
continue;
}
if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
break;
memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
print_mac(mac, mc_list->dmi_addr));
i++;
}
netif_tx_unlock_bh(dev);
if (mc_list)
return -EOVERFLOW;
return i; return i;
} }
static void lbs_set_mcast_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
struct cmd_ds_mac_multicast_adr mcast_cmd;
int dev_flags;
int nr_addrs;
int old_mac_control = priv->mac_control;
lbs_deb_enter(LBS_DEB_NET);
dev_flags = priv->dev->flags;
if (priv->mesh_dev)
dev_flags |= priv->mesh_dev->flags;
if (dev_flags & IFF_PROMISC) {
priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
CMD_ACT_MAC_MULTICAST_ENABLE);
goto out_set_mac_control;
} else if (dev_flags & IFF_ALLMULTI) {
do_allmulti:
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
CMD_ACT_MAC_MULTICAST_ENABLE);
goto out_set_mac_control;
}
/* Once for priv->dev, again for priv->mesh_dev if it exists */
nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
if (nr_addrs >= 0 && priv->mesh_dev)
nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
if (nr_addrs < 0)
goto do_allmulti;
if (nr_addrs) {
int size = offsetof(struct cmd_ds_mac_multicast_adr,
maclist[6*nr_addrs]);
mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
mcast_cmd.hdr.size = cpu_to_le16(size);
mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
} else
priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
out_set_mac_control:
if (priv->mac_control != old_mac_control)
lbs_set_mac_control(priv);
lbs_deb_leave(LBS_DEB_NET);
}
static void lbs_set_multicast_list(struct net_device *dev) static void lbs_set_multicast_list(struct net_device *dev)
{ {
struct lbs_private *priv = dev->priv; struct lbs_private *priv = dev->priv;
int old_mac_control;
DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_NET); schedule_work(&priv->mcast_work);
old_mac_control = priv->mac_control;
if (dev->flags & IFF_PROMISC) {
lbs_deb_net("enable promiscuous mode\n");
priv->mac_control |=
CMD_ACT_MAC_PROMISCUOUS_ENABLE;
priv->mac_control &=
~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
CMD_ACT_MAC_MULTICAST_ENABLE);
} else {
/* Multicast */
priv->mac_control &=
~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (dev->flags & IFF_ALLMULTI || dev->mc_count >
MRVDRV_MAX_MULTICAST_LIST_SIZE) {
lbs_deb_net( "enabling all multicast\n");
priv->mac_control |=
CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
priv->mac_control &=
~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
priv->mac_control &=
~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
if (!dev->mc_count) {
lbs_deb_net("no multicast addresses, "
"disabling multicast\n");
priv->mac_control &=
~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
int i;
priv->mac_control |=
CMD_ACT_MAC_MULTICAST_ENABLE;
priv->nr_of_multicastmacaddr =
lbs_copy_multicast_address(priv, dev);
lbs_deb_net("multicast addresses: %d\n",
dev->mc_count);
for (i = 0; i < dev->mc_count; i++) {
lbs_deb_net("Multicast address %d: %s\n",
i, print_mac(mac,
priv->multicastlist[i]));
}
/* send multicast addresses to firmware */
lbs_prepare_and_send_command(priv,
CMD_MAC_MULTICAST_ADR,
CMD_ACT_SET, 0, 0,
NULL);
}
}
}
if (priv->mac_control != old_mac_control)
lbs_set_mac_control(priv);
lbs_deb_leave(LBS_DEB_NET);
} }
/** /**
@ -689,14 +722,14 @@ static int lbs_thread(void *data)
shouldsleep = 1; /* Something is en route to the device already */ shouldsleep = 1; /* Something is en route to the device already */
else if (priv->tx_pending_len > 0) else if (priv->tx_pending_len > 0)
shouldsleep = 0; /* We've a packet to send */ shouldsleep = 0; /* We've a packet to send */
else if (priv->resp_len[priv->resp_idx])
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd) else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */ shouldsleep = 1; /* Can't send a command; one already running */
else if (!list_empty(&priv->cmdpendingq)) else if (!list_empty(&priv->cmdpendingq))
shouldsleep = 0; /* We have a command to send */ shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo)) else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */ shouldsleep = 0; /* We have an event to process */
else if (priv->resp_len[priv->resp_idx])
shouldsleep = 0; /* We have a command response */
else else
shouldsleep = 1; /* No command */ shouldsleep = 1; /* No command */
@ -749,16 +782,21 @@ static int lbs_thread(void *data)
if (priv->cmd_timed_out && priv->cur_cmd) { if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd; struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
if (++priv->nr_retries > 10) { if (++priv->nr_retries > 3) {
lbs_pr_info("Excessive timeouts submitting command %x\n", lbs_pr_info("Excessive timeouts submitting "
le16_to_cpu(cmdnode->cmdbuf->command)); "command 0x%04x\n",
le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT); lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
priv->nr_retries = 0; priv->nr_retries = 0;
if (priv->reset_card)
priv->reset_card(priv);
} else { } else {
priv->cur_cmd = NULL; priv->cur_cmd = NULL;
priv->dnld_sent = DNLD_RES_RECEIVED; priv->dnld_sent = DNLD_RES_RECEIVED;
lbs_pr_info("requeueing command %x due to timeout (#%d)\n", lbs_pr_info("requeueing command 0x%04x due "
le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); "to timeout (#%d)\n",
le16_to_cpu(cmdnode->cmdbuf->command),
priv->nr_retries);
/* Stick it back at the _top_ of the pending queue /* Stick it back at the _top_ of the pending queue
for immediate resubmission */ for immediate resubmission */
@ -949,12 +987,11 @@ static void command_timer_fn(unsigned long data)
lbs_deb_enter(LBS_DEB_CMD); lbs_deb_enter(LBS_DEB_CMD);
spin_lock_irqsave(&priv->driver_lock, flags); spin_lock_irqsave(&priv->driver_lock, flags);
if (!priv->cur_cmd) { if (!priv->cur_cmd)
lbs_pr_info("Command timer expired; no pending command\n");
goto out; goto out;
}
lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); lbs_pr_info("command 0x%04x timed out\n",
le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1; priv->cmd_timed_out = 1;
wake_up_interruptible(&priv->waitq); wake_up_interruptible(&priv->waitq);
@ -1008,7 +1045,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radioon = RADIO_ON; priv->radioon = RADIO_ON;
priv->auto_rate = 1; priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM; priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER; priv->psstate = PS_STATE_FULL_POWER;
@ -1123,6 +1160,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->work_thread = create_singlethread_workqueue("lbs_worker"); priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker); INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
sprintf(priv->mesh_ssid, "mesh"); sprintf(priv->mesh_ssid, "mesh");
@ -1159,6 +1197,7 @@ void lbs_remove_card(struct lbs_private *priv)
cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->scan_work);
cancel_delayed_work_sync(&priv->assoc_work); cancel_delayed_work_sync(&priv->assoc_work);
cancel_work_sync(&priv->mcast_work);
destroy_workqueue(priv->work_thread); destroy_workqueue(priv->work_thread);
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
@ -1224,9 +1263,11 @@ int lbs_start_card(struct lbs_private *priv)
useful */ useful */
priv->mesh_tlv = 0x100 + 291; priv->mesh_tlv = 0x100 + 291;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) {
priv->mesh_tlv = 0x100 + 37; priv->mesh_tlv = 0x100 + 37;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel))
priv->mesh_tlv = 0; priv->mesh_tlv = 0;
} }
if (priv->mesh_tlv) { if (priv->mesh_tlv) {
@ -1266,8 +1307,9 @@ void lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv); lbs_debugfs_remove_one(priv);
device_remove_file(&dev->dev, &dev_attr_lbs_rtap); device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
if (priv->mesh_tlv) if (priv->mesh_tlv) {
device_remove_file(&dev->dev, &dev_attr_lbs_mesh); device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
}
/* Flush pending command nodes */ /* Flush pending command nodes */
del_timer_sync(&priv->command_timer); del_timer_sync(&priv->command_timer);
@ -1323,6 +1365,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
#endif #endif
mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
mesh_dev->set_multicast_list = lbs_set_multicast_list;
/* Register virtual mesh interface */ /* Register virtual mesh interface */
ret = register_netdev(mesh_dev); ret = register_netdev(mesh_dev);
if (ret) { if (ret) {
@ -1334,6 +1378,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
if (ret) if (ret)
goto err_unregister; goto err_unregister;
lbs_persist_config_init(mesh_dev);
/* Everything successful */ /* Everything successful */
ret = 0; ret = 0;
goto done; goto done;
@ -1360,8 +1406,9 @@ static void lbs_remove_mesh(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MESH); lbs_deb_enter(LBS_DEB_MESH);
netif_stop_queue(mesh_dev); netif_stop_queue(mesh_dev);
netif_carrier_off(priv->mesh_dev); netif_carrier_off(mesh_dev);
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev); unregister_netdev(mesh_dev);
priv->mesh_dev = NULL; priv->mesh_dev = NULL;
free_netdev(mesh_dev); free_netdev(mesh_dev);
@ -1555,7 +1602,6 @@ static int lbs_add_rtap(struct lbs_private *priv)
rtap_dev->stop = lbs_rtap_stop; rtap_dev->stop = lbs_rtap_stop;
rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->get_stats = lbs_rtap_get_stats;
rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
rtap_dev->set_multicast_list = lbs_set_multicast_list;
rtap_dev->priv = priv; rtap_dev->priv = priv;
SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);

View File

@ -0,0 +1,453 @@
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
#include "cmd.h"
static int mesh_get_default_parameters(struct device *dev,
struct mrvl_mesh_defaults *defs)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
int ret;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
CMD_TYPE_MESH_GET_DEFAULTS);
if (ret)
return -EOPNOTSUPP;
memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
return 0;
}
/**
* @brief Get function for sysfs attribute bootflag
*/
static ssize_t bootflag_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
}
/**
* @brief Set function for sysfs attribute bootflag
*/
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
cmd.length = cpu_to_le16(sizeof(uint32_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTFLAG);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute boottime
*/
static ssize_t boottime_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "0x%x\n", defs.boottime);
}
/**
* @brief Set function for sysfs attribute boottime
*/
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* A too small boot time will result in the device booting into
* standalone (no-host) mode before the host can take control of it,
* so the change will be hard to revert. This may be a desired
* feature (e.g to configure a very fast boot time for devices that
* will not be attached to a host), but dangerous. So I'm enforcing a
* lower limit of 20 seconds: remove and recompile the driver if this
* does not work for you.
*/
datum = (datum < 20) ? 20 : datum;
cmd.data[0] = datum;
cmd.length = cpu_to_le16(sizeof(uint8_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTTIME);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute channel
*/
static ssize_t channel_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel));
}
/**
* @brief Set function for sysfs attribute channel
*/
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
uint16_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%hx", &datum);
if (ret != 1 || datum < 1 || datum > 11)
return -EINVAL;
*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
cmd.length = cpu_to_le16(sizeof(uint16_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_DEF_CHANNEL);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mrvl_mesh_defaults defs;
int maxlen;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
lbs_pr_err("inconsistent mesh ID length");
defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
}
/* SSID not null terminated: reserve room for \0 + \n */
maxlen = defs.meshie.val.mesh_id_len + 2;
maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
}
/**
* @brief Set function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
int len;
int ret;
if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ie = (struct mrvl_meshie *) &cmd.data[0];
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
len = count - 1;
memcpy(ie->val.mesh_id, buf, len);
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
}
/**
* @brief Set function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update protocol id */
ie->val.active_protocol_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute metric_id
*/
static ssize_t metric_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
}
/**
* @brief Set function for sysfs attribute metric_id
*/
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update metric id */
ie->val.active_metric_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute capability
*/
static ssize_t capability_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
}
/**
* @brief Set function for sysfs attribute capability
*/
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update value */
ie->val.mesh_capability = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
static struct attribute *boot_opts_attrs[] = {
&dev_attr_bootflag.attr,
&dev_attr_boottime.attr,
&dev_attr_channel.attr,
NULL
};
static struct attribute_group boot_opts_group = {
.name = "boot_options",
.attrs = boot_opts_attrs,
};
static struct attribute *mesh_ie_attrs[] = {
&dev_attr_mesh_id.attr,
&dev_attr_protocol_id.attr,
&dev_attr_metric_id.attr,
&dev_attr_capability.attr,
NULL
};
static struct attribute_group mesh_ie_group = {
.name = "mesh_ie",
.attrs = mesh_ie_attrs,
};
void lbs_persist_config_init(struct net_device *dev)
{
int ret;
ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
}
void lbs_persist_config_remove(struct net_device *dev)
{
sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
}

View File

@ -237,7 +237,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
/* Take the data rate from the rxpd structure /* Take the data rate from the rxpd structure
* only if the rate is auto * only if the rate is auto
*/ */
if (priv->auto_rate) if (priv->enablehwauto)
priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
lbs_compute_rssi(priv, p_rx_pd); lbs_compute_rssi(priv, p_rx_pd);
@ -383,7 +383,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
/* Take the data rate from the rxpd structure /* Take the data rate from the rxpd structure
* only if the rate is auto * only if the rate is auto
*/ */
if (priv->auto_rate) if (priv->enablehwauto)
priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
lbs_compute_rssi(priv, prxpd); lbs_compute_rssi(priv, prxpd);

View File

@ -6,6 +6,8 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/wireless.h>
#include <net/ieee80211.h>
struct ieeetypes_cfparamset { struct ieeetypes_cfparamset {
u8 elementid; u8 elementid;
@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv {
struct led_bhv ledbhv[1]; struct led_bhv ledbhv[1];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Meant to be packed as the value member of a struct ieee80211_info_element.
* Note that the len member of the ieee80211_info_element varies depending on
* the mesh_id_len */
struct mrvl_meshie_val {
uint8_t oui[P80211_OUI_LEN];
uint8_t type;
uint8_t subtype;
uint8_t version;
uint8_t active_protocol_id;
uint8_t active_metric_id;
uint8_t mesh_capability;
uint8_t mesh_id_len;
uint8_t mesh_id[IW_ESSID_MAX_SIZE];
} __attribute__ ((packed));
struct mrvl_meshie {
struct ieee80211_info_element hdr;
struct mrvl_meshie_val val;
} __attribute__ ((packed));
struct mrvl_mesh_defaults {
__le32 bootflag;
uint8_t boottime;
uint8_t reserved;
__le16 channel;
struct mrvl_meshie meshie;
} __attribute__ ((packed));
#endif #endif

View File

@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
else if (priv->mode == IW_MODE_ADHOC) else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv); lbs_stop_adhoc_network(priv);
} }
lbs_mesh_config(priv, 1, fwrq->m); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
lbs_update_channel(priv); lbs_update_channel(priv);
ret = 0; ret = 0;
@ -1021,29 +1021,38 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_enter(LBS_DEB_WEXT);
lbs_deb_wext("vwrq->value %d\n", vwrq->value); lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
if (vwrq->fixed && vwrq->value == -1)
goto out;
/* Auto rate? */ /* Auto rate? */
if (vwrq->value == -1) { priv->enablehwauto = !vwrq->fixed;
priv->auto_rate = 1;
if (vwrq->value == -1)
priv->cur_rate = 0; priv->cur_rate = 0;
} else { else {
if (vwrq->value % 100000) if (vwrq->value % 100000)
goto out; goto out;
new_rate = vwrq->value / 500000;
priv->cur_rate = new_rate;
/* the rest is only needed for lbs_set_data_rate() */
memset(rates, 0, sizeof(rates)); memset(rates, 0, sizeof(rates));
copy_active_data_rates(priv, rates); copy_active_data_rates(priv, rates);
new_rate = vwrq->value / 500000;
if (!memchr(rates, new_rate, sizeof(rates))) { if (!memchr(rates, new_rate, sizeof(rates))) {
lbs_pr_alert("fixed data rate 0x%X out of range\n", lbs_pr_alert("fixed data rate 0x%X out of range\n",
new_rate); new_rate);
goto out; goto out;
} }
priv->cur_rate = new_rate;
priv->auto_rate = 0;
} }
ret = lbs_set_data_rate(priv, new_rate); /* Try the newer command first (Firmware Spec 5.1 and above) */
ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
/* Fallback to older version */
if (ret)
ret = lbs_set_data_rate(priv, new_rate);
out: out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@ -1060,7 +1069,7 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
if (priv->connect_status == LBS_CONNECTED) { if (priv->connect_status == LBS_CONNECTED) {
vwrq->value = priv->cur_rate * 500000; vwrq->value = priv->cur_rate * 500000;
if (priv->auto_rate) if (priv->enablehwauto)
vwrq->fixed = 0; vwrq->fixed = 0;
else else
vwrq->fixed = 1; vwrq->fixed = 1;
@ -2011,7 +2020,8 @@ static int lbs_mesh_set_essid(struct net_device *dev,
priv->mesh_ssid_len = dwrq->length; priv->mesh_ssid_len = dwrq->length;
} }
lbs_mesh_config(priv, 1, priv->curbssparams.channel); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel);
out: out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret; return ret;

View File

@ -375,9 +375,6 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
int i; int i;
/* ieee80211_start_queues is great if all queues are really empty.
* But, what if some are full? */
for (i = 0; i < dev->queues; i++) for (i = 0; i < dev->queues; i++)
if (priv->tx_stats[i].len < priv->tx_stats[i].limit) if (priv->tx_stats[i].len < priv->tx_stats[i].limit)
ieee80211_wake_queue(dev, i); ieee80211_wake_queue(dev, i);
@ -395,44 +392,42 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
u32 last_addr = priv->rx_start; u32 last_addr = priv->rx_start;
while (entry != (struct sk_buff *)&priv->tx_queue) { while (entry != (struct sk_buff *)&priv->tx_queue) {
range = (struct memrecord *)&entry->cb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
range = (void *)info->driver_data;
if (range->start_addr == addr) { if (range->start_addr == addr) {
struct ieee80211_tx_status status;
struct p54_control_hdr *entry_hdr; struct p54_control_hdr *entry_hdr;
struct p54_tx_control_allocdata *entry_data; struct p54_tx_control_allocdata *entry_data;
int pad = 0; int pad = 0;
if (entry->next != (struct sk_buff *)&priv->tx_queue) if (entry->next != (struct sk_buff *)&priv->tx_queue) {
freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr; struct ieee80211_tx_info *ni;
else struct memrecord *mr;
ni = IEEE80211_SKB_CB(entry->next);
mr = (struct memrecord *)ni->driver_data;
freed = mr->start_addr - last_addr;
} else
freed = priv->rx_end - last_addr; freed = priv->rx_end - last_addr;
last_addr = range->end_addr; last_addr = range->end_addr;
__skb_unlink(entry, &priv->tx_queue); __skb_unlink(entry, &priv->tx_queue);
if (!range->control) { memset(&info->status, 0, sizeof(info->status));
kfree_skb(entry); priv->tx_stats[skb_get_queue_mapping(skb)].len--;
break;
}
memset(&status, 0, sizeof(status));
memcpy(&status.control, range->control,
sizeof(status.control));
kfree(range->control);
priv->tx_stats[status.control.queue].len--;
entry_hdr = (struct p54_control_hdr *) entry->data; entry_hdr = (struct p54_control_hdr *) entry->data;
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
pad = entry_data->align[0]; pad = entry_data->align[0];
if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (!(payload->status & 0x01)) if (!(payload->status & 0x01))
status.flags |= IEEE80211_TX_STATUS_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
else else
status.excessive_retries = 1; info->status.excessive_retries = 1;
} }
status.retry_count = payload->retries - 1; info->status.retry_count = payload->retries - 1;
status.ack_signal = le16_to_cpu(payload->ack_rssi); info->status.ack_signal = le16_to_cpu(payload->ack_rssi);
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
ieee80211_tx_status_irqsafe(dev, entry, &status); ieee80211_tx_status_irqsafe(dev, entry);
break; break;
} else } else
last_addr = range->end_addr; last_addr = range->end_addr;
@ -497,13 +492,11 @@ EXPORT_SYMBOL_GPL(p54_rx);
* allocated areas. * allocated areas.
*/ */
static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
struct p54_control_hdr *data, u32 len, struct p54_control_hdr *data, u32 len)
struct ieee80211_tx_control *control)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *entry = priv->tx_queue.next;
struct sk_buff *target_skb = NULL; struct sk_buff *target_skb = NULL;
struct memrecord *range;
u32 last_addr = priv->rx_start; u32 last_addr = priv->rx_start;
u32 largest_hole = 0; u32 largest_hole = 0;
u32 target_addr = priv->rx_start; u32 target_addr = priv->rx_start;
@ -515,7 +508,8 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
left = skb_queue_len(&priv->tx_queue); left = skb_queue_len(&priv->tx_queue);
while (left--) { while (left--) {
u32 hole_size; u32 hole_size;
range = (struct memrecord *)&entry->cb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
struct memrecord *range = (void *)info->driver_data;
hole_size = range->start_addr - last_addr; hole_size = range->start_addr - last_addr;
if (!target_skb && hole_size >= len) { if (!target_skb && hole_size >= len) {
target_skb = entry->prev; target_skb = entry->prev;
@ -530,17 +524,18 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
target_skb = priv->tx_queue.prev; target_skb = priv->tx_queue.prev;
largest_hole = max(largest_hole, priv->rx_end - last_addr - len); largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
if (!skb_queue_empty(&priv->tx_queue)) { if (!skb_queue_empty(&priv->tx_queue)) {
range = (struct memrecord *)&target_skb->cb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
struct memrecord *range = (void *)info->driver_data;
target_addr = range->end_addr; target_addr = range->end_addr;
} }
} else } else
largest_hole = max(largest_hole, priv->rx_end - last_addr); largest_hole = max(largest_hole, priv->rx_end - last_addr);
if (skb) { if (skb) {
range = (struct memrecord *)&skb->cb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct memrecord *range = (void *)info->driver_data;
range->start_addr = target_addr; range->start_addr = target_addr;
range->end_addr = target_addr + len; range->end_addr = target_addr + len;
range->control = control;
__skb_queue_after(&priv->tx_queue, target_skb, skb); __skb_queue_after(&priv->tx_queue, target_skb, skb);
if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
sizeof(struct p54_control_hdr)) sizeof(struct p54_control_hdr))
@ -551,32 +546,27 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
data->req_id = cpu_to_le32(target_addr + 0x70); data->req_id = cpu_to_le32(target_addr + 0x70);
} }
static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_queue_stats *current_queue; struct ieee80211_tx_queue_stats *current_queue;
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct p54_control_hdr *hdr; struct p54_control_hdr *hdr;
struct p54_tx_control_allocdata *txhdr; struct p54_tx_control_allocdata *txhdr;
struct ieee80211_tx_control *control_copy;
size_t padding, len; size_t padding, len;
u8 rate; u8 rate;
current_queue = &priv->tx_stats[control->queue]; current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
if (unlikely(current_queue->len > current_queue->limit)) if (unlikely(current_queue->len > current_queue->limit))
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
current_queue->len++; current_queue->len++;
current_queue->count++; current_queue->count++;
if (current_queue->len == current_queue->limit) if (current_queue->len == current_queue->limit)
ieee80211_stop_queue(dev, control->queue); ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
len = skb->len; len = skb->len;
control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
if (control_copy)
memcpy(control_copy, control, sizeof(*control));
txhdr = (struct p54_tx_control_allocdata *) txhdr = (struct p54_tx_control_allocdata *)
skb_push(skb, sizeof(*txhdr) + padding); skb_push(skb, sizeof(*txhdr) + padding);
hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
@ -586,35 +576,37 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
else else
hdr->magic1 = cpu_to_le16(0x0010); hdr->magic1 = cpu_to_le16(0x0010);
hdr->len = cpu_to_le16(len); hdr->len = cpu_to_le16(len);
hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1); hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
hdr->retry1 = hdr->retry2 = control->retry_limit; hdr->retry1 = hdr->retry2 = info->control.retry_limit;
p54_assign_address(dev, skb, hdr, skb->len, control_copy);
memset(txhdr->wep_key, 0x0, 16); memset(txhdr->wep_key, 0x0, 16);
txhdr->padding = 0; txhdr->padding = 0;
txhdr->padding2 = 0; txhdr->padding2 = 0;
/* TODO: add support for alternate retry TX rates */ /* TODO: add support for alternate retry TX rates */
rate = control->tx_rate->hw_value; rate = ieee80211_get_tx_rate(dev, info)->hw_value;
if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
rate |= 0x10; rate |= 0x10;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rate |= 0x40; rate |= 0x40;
else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
rate |= 0x20; rate |= 0x20;
memset(txhdr->rateset, rate, 8); memset(txhdr->rateset, rate, 8);
txhdr->wep_key_present = 0; txhdr->wep_key_present = 0;
txhdr->wep_key_len = 0; txhdr->wep_key_len = 0;
txhdr->frame_type = cpu_to_le32(control->queue + 4); txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4);
txhdr->magic4 = 0; txhdr->magic4 = 0;
txhdr->antenna = (control->antenna_sel_tx == 0) ? txhdr->antenna = (info->antenna_sel_tx == 0) ?
2 : control->antenna_sel_tx - 1; 2 : info->antenna_sel_tx - 1;
txhdr->output_power = 0x7f; // HW Maximum txhdr->output_power = 0x7f; // HW Maximum
txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ? txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23)); 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
if (padding) if (padding)
txhdr->align[0] = padding; txhdr->align[0] = padding;
/* modifies skb->cb and with it info, so must be last! */
p54_assign_address(dev, skb, hdr, skb->len);
priv->tx(dev, hdr, skb->len, 0); priv->tx(dev, hdr, skb->len, 0);
return 0; return 0;
} }
@ -637,7 +629,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
filter = (struct p54_tx_control_filter *) hdr->data; filter = (struct p54_tx_control_filter *) hdr->data;
hdr->magic1 = cpu_to_le16(0x8001); hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*filter)); hdr->len = cpu_to_le16(sizeof(*filter));
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
filter->filter_type = cpu_to_le16(filter_type); filter->filter_type = cpu_to_le16(filter_type);
@ -681,7 +673,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
hdr->magic1 = cpu_to_le16(0x8001); hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*chan)); hdr->len = cpu_to_le16(sizeof(*chan));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len);
chan->magic1 = cpu_to_le16(0x1); chan->magic1 = cpu_to_le16(0x1);
chan->magic2 = cpu_to_le16(0x0); chan->magic2 = cpu_to_le16(0x0);
@ -754,7 +746,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
hdr->magic1 = cpu_to_le16(0x8001); hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*led)); hdr->len = cpu_to_le16(sizeof(*led));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
led = (struct p54_tx_control_led *) hdr->data; led = (struct p54_tx_control_led *) hdr->data;
led->mode = cpu_to_le16(mode); led->mode = cpu_to_le16(mode);
@ -804,7 +796,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev)
hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL); p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf));
vdcf = (struct p54_tx_control_vdcf *) hdr->data; vdcf = (struct p54_tx_control_vdcf *) hdr->data;
@ -840,12 +832,8 @@ static void p54_stop(struct ieee80211_hw *dev)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct sk_buff *skb; struct sk_buff *skb;
while ((skb = skb_dequeue(&priv->tx_queue))) { while ((skb = skb_dequeue(&priv->tx_queue)))
struct memrecord *range = (struct memrecord *)&skb->cb;
if (range->control)
kfree(range->control);
kfree_skb(skb); kfree_skb(skb);
}
priv->stop(dev); priv->stop(dev);
priv->mode = IEEE80211_IF_TYPE_INVALID; priv->mode = IEEE80211_IF_TYPE_INVALID;
} }

View File

@ -152,7 +152,6 @@ struct pda_pa_curve_data {
struct memrecord { struct memrecord {
u32 start_addr; u32 start_addr;
u32 end_addr; u32 end_addr;
struct ieee80211_tx_control *control;
}; };
struct p54_eeprom_lm86 { struct p54_eeprom_lm86 {

View File

@ -665,7 +665,7 @@ static int p54p_resume(struct pci_dev *pdev)
if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
p54p_open(dev); p54p_open(dev);
ieee80211_start_queues(dev); ieee80211_wake_queues(dev);
} }
return 0; return 0;

View File

@ -1108,7 +1108,7 @@ static int rndis_iw_get_range(struct net_device *dev,
/* fill in 802.11g rates */ /* fill in 802.11g rates */
if (has_80211g_rates) { if (has_80211g_rates) {
num = range->num_bitrates; num = range->num_bitrates;
for (i = 0; i < sizeof(rates_80211g); i++) { for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) {
for (j = 0; j < num; j++) { for (j = 0; j < num; j++) {
if (range->bitrate[j] == if (range->bitrate[j] ==
rates_80211g[i] * 1000000) rates_80211g[i] * 1000000)

View File

@ -620,48 +620,38 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_rx->desc, 2, &word); rt2x00_desc_read(entry_priv->desc, 2, &word);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
entry->queue->data_size); entry->queue->data_size);
rt2x00_desc_write(priv_rx->desc, 2, word); rt2x00_desc_write(entry_priv->desc, 2, word);
rt2x00_desc_read(priv_rx->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_desc_write(priv_rx->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
rt2x00_desc_write(priv_rx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_tx->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
rt2x00_desc_write(priv_tx->desc, 1, word);
rt2x00_desc_read(priv_tx->desc, 2, &word);
rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
entry->queue->data_size);
rt2x00_desc_write(priv_tx->desc, 2, word);
rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
rt2x00_desc_write(priv_tx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
{ {
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry_priv_pci_tx *priv_tx;
u32 reg; u32 reg;
/* /*
@ -674,28 +664,28 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
priv_tx = rt2x00dev->tx[1].entries[0].priv_data; entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
priv_tx = rt2x00dev->tx[0].entries[0].priv_data; entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
@ -703,9 +693,10 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
priv_rx = rt2x00dev->rx->entries[0].priv_data; entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg); rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0; return 0;
@ -1001,17 +992,22 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
*/ */
static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc)
struct ieee80211_tx_control *control)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
u32 word; u32 word;
/* /*
* Start writing the descriptor words. * Start writing the descriptor words.
*/ */
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word); rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_desc_write(txd, 2, word); rt2x00_desc_write(txd, 2, word);
@ -1046,8 +1042,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags & test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_desc_write(txd, 0, word); rt2x00_desc_write(txd, 0, word);
} }
@ -1083,16 +1078,15 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
static void rt2400pci_fill_rxdone(struct queue_entry *entry, static void rt2400pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc) struct rxdone_entry_desc *rxdesc)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0; u32 word0;
u32 word2; u32 word2;
u32 word3; u32 word3;
rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(entry_priv->desc, 0, &word0);
rt2x00_desc_read(priv_rx->desc, 2, &word2); rt2x00_desc_read(entry_priv->desc, 2, &word2);
rt2x00_desc_read(priv_rx->desc, 3, &word3); rt2x00_desc_read(entry_priv->desc, 3, &word3);
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@ -1108,7 +1102,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
entry->queue->rt2x00dev->rssi_offset; entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->dev_flags = RXDONE_SIGNAL_PLCP; rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS; rxdesc->dev_flags |= RXDONE_MY_BSS;
} }
@ -1120,15 +1114,15 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx) const enum data_queue_qid queue_idx)
{ {
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
struct queue_entry_priv_pci_tx *priv_tx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry *entry; struct queue_entry *entry;
struct txdone_entry_desc txdesc; struct txdone_entry_desc txdesc;
u32 word; u32 word;
while (!rt2x00queue_empty(queue)) { while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
priv_tx = entry->priv_data; entry_priv = entry->priv_data;
rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID)) !rt2x00_get_field32(word, TXD_W0_VALID))
@ -1137,7 +1131,18 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
/* /*
* Obtain the status about this packet. * Obtain the status about this packet.
*/ */
txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); txdesc.flags = 0;
switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
case 0: /* Success */
case 1: /* Success with retry */
__set_bit(TXDONE_SUCCESS, &txdesc.flags);
break;
case 2: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
/* Don't break, this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc); rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@ -1364,7 +1369,6 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -1480,18 +1484,27 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
return tsf; return tsf;
} }
static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct queue_entry_priv_pci_tx *priv_tx; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
u32 reg; u32 reg;
if (unlikely(!intf->beacon)) if (unlikely(!intf->beacon))
return -ENOBUFS; return -ENOBUFS;
priv_tx = intf->beacon->priv_data; entry_priv = intf->beacon->priv_data;
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
intf->beacon->skb = skb;
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
@ -1501,7 +1514,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data; skbdesc->data = skb->data;
skbdesc->data_len = skb->len; skbdesc->data_len = skb->len;
skbdesc->desc = priv_tx->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon; skbdesc->entry = intf->beacon;
@ -1520,8 +1533,8 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(entry_priv->data, skb->data, skb->len);
memcpy(priv_tx->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
return 0; return 0;
@ -1581,28 +1594,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = {
.entry_num = RX_ENTRIES, .entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE, .desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_rx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2400pci_queue_tx = { static const struct data_queue_desc rt2400pci_queue_tx = {
.entry_num = TX_ENTRIES, .entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2400pci_queue_bcn = { static const struct data_queue_desc rt2400pci_queue_bcn = {
.entry_num = BEACON_ENTRIES, .entry_num = BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE, .data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2400pci_queue_atim = { static const struct data_queue_desc rt2400pci_queue_atim = {
.entry_num = ATIM_ENTRIES, .entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct rt2x00_ops rt2400pci_ops = { static const struct rt2x00_ops rt2400pci_ops = {
@ -1611,6 +1624,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2400pci_queue_rx, .rx = &rt2400pci_queue_rx,
.tx = &rt2400pci_queue_tx, .tx = &rt2400pci_queue_tx,
.bcn = &rt2400pci_queue_bcn, .bcn = &rt2400pci_queue_bcn,

View File

@ -51,6 +51,11 @@
#define BBP_SIZE 0x0020 #define BBP_SIZE 0x0020
#define RF_SIZE 0x0010 #define RF_SIZE 0x0010
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.

View File

@ -715,38 +715,33 @@ dynamic_cca_tune:
static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_rx->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma); rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_desc_write(priv_rx->desc, 1, word); rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
rt2x00_desc_write(priv_rx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_tx->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
rt2x00_desc_write(priv_tx->desc, 1, word);
rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
rt2x00_desc_write(priv_tx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
{ {
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry_priv_pci_tx *priv_tx;
u32 reg; u32 reg;
/* /*
@ -759,28 +754,28 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit); rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg); rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
priv_tx = rt2x00dev->tx[1].entries[0].priv_data; entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg); rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
priv_tx = rt2x00dev->tx[0].entries[0].priv_data; entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg); rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
priv_tx = rt2x00dev->bcn[1].entries[0].priv_data; entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg); rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
priv_tx = rt2x00dev->bcn[0].entries[0].priv_data; entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg); rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER, rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg); rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg); rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
@ -788,9 +783,10 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit); rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg); rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
priv_rx = rt2x00dev->rx->entries[0].priv_data; entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg); rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma); rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg); rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0; return 0;
@ -1155,16 +1151,20 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
*/ */
static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc)
struct ieee80211_tx_control *control)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
u32 word; u32 word;
/* /*
* Start writing the descriptor words. * Start writing the descriptor words.
*/ */
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
rt2x00_desc_write(entry_priv->desc, 1, word);
rt2x00_desc_read(txd, 2, &word); rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs);
@ -1198,9 +1198,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags & test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word); rt2x00_desc_write(txd, 0, word);
} }
@ -1237,14 +1235,13 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
static void rt2500pci_fill_rxdone(struct queue_entry *entry, static void rt2500pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc) struct rxdone_entry_desc *rxdesc)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0; u32 word0;
u32 word2; u32 word2;
rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(entry_priv->desc, 0, &word0);
rt2x00_desc_read(priv_rx->desc, 2, &word2); rt2x00_desc_read(entry_priv->desc, 2, &word2);
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@ -1261,7 +1258,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry,
entry->queue->rt2x00dev->rssi_offset; entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM)) if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@ -1275,15 +1271,15 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx) const enum data_queue_qid queue_idx)
{ {
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
struct queue_entry_priv_pci_tx *priv_tx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry *entry; struct queue_entry *entry;
struct txdone_entry_desc txdesc; struct txdone_entry_desc txdesc;
u32 word; u32 word;
while (!rt2x00queue_empty(queue)) { while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
priv_tx = entry->priv_data; entry_priv = entry->priv_data;
rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID)) !rt2x00_get_field32(word, TXD_W0_VALID))
@ -1292,7 +1288,18 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
/* /*
* Obtain the status about this packet. * Obtain the status about this packet.
*/ */
txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT); txdesc.flags = 0;
switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
case 0: /* Success */
case 1: /* Success with retry */
__set_bit(TXDONE_SUCCESS, &txdesc.flags);
break;
case 2: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
/* Don't break, this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc); rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@ -1684,7 +1691,6 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -1793,19 +1799,28 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
return tsf; return tsf;
} }
static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct queue_entry_priv_pci_tx *priv_tx; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
u32 reg; u32 reg;
if (unlikely(!intf->beacon)) if (unlikely(!intf->beacon))
return -ENOBUFS; return -ENOBUFS;
priv_tx = intf->beacon->priv_data; entry_priv = intf->beacon->priv_data;
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
intf->beacon->skb = skb;
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
@ -1815,7 +1830,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data; skbdesc->data = skb->data;
skbdesc->data_len = skb->len; skbdesc->data_len = skb->len;
skbdesc->desc = priv_tx->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon; skbdesc->entry = intf->beacon;
@ -1834,8 +1849,8 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
rt2x00lib_write_tx_desc(rt2x00dev, skb, control); memcpy(entry_priv->data, skb->data, skb->len);
memcpy(priv_tx->data, skb->data, skb->len); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
return 0; return 0;
@ -1895,28 +1910,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = {
.entry_num = RX_ENTRIES, .entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE, .desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_rx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2500pci_queue_tx = { static const struct data_queue_desc rt2500pci_queue_tx = {
.entry_num = TX_ENTRIES, .entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2500pci_queue_bcn = { static const struct data_queue_desc rt2500pci_queue_bcn = {
.entry_num = BEACON_ENTRIES, .entry_num = BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE, .data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt2500pci_queue_atim = { static const struct data_queue_desc rt2500pci_queue_atim = {
.entry_num = ATIM_ENTRIES, .entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct rt2x00_ops rt2500pci_ops = { static const struct rt2x00_ops rt2500pci_ops = {
@ -1925,6 +1940,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500pci_queue_rx, .rx = &rt2500pci_queue_rx,
.tx = &rt2500pci_queue_tx, .tx = &rt2500pci_queue_tx,
.bcn = &rt2500pci_queue_bcn, .bcn = &rt2500pci_queue_bcn,

View File

@ -62,6 +62,11 @@
#define BBP_SIZE 0x0040 #define BBP_SIZE 0x0040
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.

View File

@ -1033,8 +1033,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
*/ */
static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc)
struct ieee80211_tx_control *control)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
@ -1058,7 +1057,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 2, word); rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 0, &word); rt2x00_desc_read(txd, 0, &word);
rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK, rt2x00_set_field32(&word, TXD_W0_ACK,
@ -1068,7 +1067,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_OFDM, rt2x00_set_field32(&word, TXD_W0_OFDM,
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
!!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
@ -1125,30 +1124,32 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
static void rt2500usb_fill_rxdone(struct queue_entry *entry, static void rt2500usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc) struct rxdone_entry_desc *rxdesc)
{ {
struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = __le32 *rxd =
(__le32 *)(entry->skb->data + (__le32 *)(entry->skb->data +
(priv_rx->urb->actual_length - entry->queue->desc_size)); (entry_priv->urb->actual_length -
unsigned int offset = entry->queue->desc_size + 2; entry->queue->desc_size));
u32 word0; u32 word0;
u32 word1; u32 word1;
/* /*
* Copy descriptor to the available headroom inside the skbuffer. * Copy descriptor to the skb->cb array, this has 2 benefits:
* 1) Each descriptor word is 4 byte aligned.
* 2) Descriptor is safe from moving of frame data in rt2x00usb.
*/ */
skb_push(entry->skb, offset); skbdesc->desc_len =
memcpy(entry->skb->data, rxd, entry->queue->desc_size); min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
rxd = (__le32 *)entry->skb->data; memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
skbdesc->desc = entry->skb->cb;
rxd = (__le32 *)skbdesc->desc;
/* /*
* The descriptor is now aligned to 4 bytes and thus it is * It is now safe to read the descriptor on all architectures.
* now safe to read it on all architectures.
*/ */
rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1); rt2x00_desc_read(rxd, 1, &word1);
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@ -1165,7 +1166,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
entry->queue->rt2x00dev->rssi_offset; entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM)) if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@ -1174,16 +1174,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
/* /*
* Adjust the skb memory window to the frame boundaries. * Adjust the skb memory window to the frame boundaries.
*/ */
skb_pull(entry->skb, offset);
skb_trim(entry->skb, rxdesc->size); skb_trim(entry->skb, rxdesc->size);
/*
* Set descriptor and data pointer.
*/
skbdesc->data = entry->skb->data; skbdesc->data = entry->skb->data;
skbdesc->data_len = rxdesc->size; skbdesc->data_len = rxdesc->size;
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
} }
/* /*
@ -1192,7 +1185,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
static void rt2500usb_beacondone(struct urb *urb) static void rt2500usb_beacondone(struct urb *urb)
{ {
struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry *entry = (struct queue_entry *)urb->context;
struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
return; return;
@ -1203,9 +1196,9 @@ static void rt2500usb_beacondone(struct urb *urb)
* Otherwise we should free the sk_buffer, the device * Otherwise we should free the sk_buffer, the device
* should be doing the rest of the work now. * should be doing the rest of the work now.
*/ */
if (priv_bcn->guardian_urb == urb) { if (bcn_priv->guardian_urb == urb) {
usb_submit_urb(priv_bcn->urb, GFP_ATOMIC); usb_submit_urb(bcn_priv->urb, GFP_ATOMIC);
} else if (priv_bcn->urb == urb) { } else if (bcn_priv->urb == urb) {
dev_kfree_skb(entry->skb); dev_kfree_skb(entry->skb);
entry->skb = NULL; entry->skb = NULL;
} }
@ -1591,7 +1584,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -1674,15 +1666,15 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/* /*
* IEEE80211 stack callback functions. * IEEE80211 stack callback functions.
*/ */
static int rt2500usb_beacon_update(struct ieee80211_hw *hw, static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct sk_buff *skb,
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct rt2x00_intf *intf = vif_to_intf(control->vif); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct queue_entry_priv_usb_bcn *priv_bcn; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct queue_entry_priv_usb_bcn *bcn_priv;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
int pipe = usb_sndbulkpipe(usb_dev, 1); int pipe = usb_sndbulkpipe(usb_dev, 1);
int length; int length;
u16 reg; u16 reg;
@ -1690,7 +1682,15 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
if (unlikely(!intf->beacon)) if (unlikely(!intf->beacon))
return -ENOBUFS; return -ENOBUFS;
priv_bcn = intf->beacon->priv_data; bcn_priv = intf->beacon->priv_data;
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
intf->beacon->skb = skb;
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/* /*
* Add the descriptor in front of the skb. * Add the descriptor in front of the skb.
@ -1720,7 +1720,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0); rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2x00lib_write_tx_desc(rt2x00dev, skb, control); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
/* /*
* USB devices cannot blindly pass the skb->len as the * USB devices cannot blindly pass the skb->len as the
@ -1729,7 +1729,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
*/ */
length = rt2500usb_get_tx_data_len(rt2x00dev, skb); length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe, usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
skb->data, length, rt2500usb_beacondone, skb->data, length, rt2500usb_beacondone,
intf->beacon); intf->beacon);
@ -1738,15 +1738,15 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
* We only need a single byte, so lets recycle * We only need a single byte, so lets recycle
* the 'flags' field we are not using for beacons. * the 'flags' field we are not using for beacons.
*/ */
priv_bcn->guardian_data = 0; bcn_priv->guardian_data = 0;
usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe, usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
&priv_bcn->guardian_data, 1, rt2500usb_beacondone, &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
intf->beacon); intf->beacon);
/* /*
* Send out the guardian byte. * Send out the guardian byte.
*/ */
usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC); usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
/* /*
* Enable beacon generation. * Enable beacon generation.
@ -1797,14 +1797,14 @@ static const struct data_queue_desc rt2500usb_queue_rx = {
.entry_num = RX_ENTRIES, .entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE, .desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_rx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct data_queue_desc rt2500usb_queue_tx = { static const struct data_queue_desc rt2500usb_queue_tx = {
.entry_num = TX_ENTRIES, .entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct data_queue_desc rt2500usb_queue_bcn = { static const struct data_queue_desc rt2500usb_queue_bcn = {
@ -1818,7 +1818,7 @@ static const struct data_queue_desc rt2500usb_queue_atim = {
.entry_num = ATIM_ENTRIES, .entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct rt2x00_ops rt2500usb_ops = { static const struct rt2x00_ops rt2500usb_ops = {
@ -1827,6 +1827,7 @@ static const struct rt2x00_ops rt2500usb_ops = {
.max_ap_intf = 1, .max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt2500usb_queue_rx, .rx = &rt2500usb_queue_rx,
.tx = &rt2500usb_queue_tx, .tx = &rt2500usb_queue_tx,
.bcn = &rt2500usb_queue_bcn, .bcn = &rt2500usb_queue_bcn,

View File

@ -62,6 +62,11 @@
#define BBP_SIZE 0x0060 #define BBP_SIZE 0x0060
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 2
/* /*
* Control/Status Registers(CSR). * Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us. * Some values are set in TU, whereas 1 TU == 1024 us.

View File

@ -44,7 +44,7 @@
/* /*
* Module information. * Module information.
*/ */
#define DRV_VERSION "2.1.5" #define DRV_VERSION "2.1.6"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com" #define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/* /*
@ -540,11 +540,9 @@ struct rt2x00lib_ops {
*/ */
void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc);
struct ieee80211_tx_control *control);
int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct sk_buff *skb, struct data_queue *queue, struct sk_buff *skb);
struct ieee80211_tx_control *control);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb); struct sk_buff *skb);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
@ -592,6 +590,7 @@ struct rt2x00_ops {
const unsigned int max_ap_intf; const unsigned int max_ap_intf;
const unsigned int eeprom_size; const unsigned int eeprom_size;
const unsigned int rf_size; const unsigned int rf_size;
const unsigned int tx_queues;
const struct data_queue_desc *rx; const struct data_queue_desc *rx;
const struct data_queue_desc *tx; const struct data_queue_desc *tx;
const struct data_queue_desc *bcn; const struct data_queue_desc *bcn;
@ -926,6 +925,39 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
return ((size * 8 * 10) % rate); return ((size * 8 * 10) % rate);
} }
/**
* rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
* @entry: The entry which will be used to transfer the TX frame.
* @txdesc: rt2x00 TX descriptor which will be initialized by this function.
*
* This function will initialize the &struct txentry_desc based on information
* from mac80211. This descriptor can then be used by rt2x00lib and the drivers
* to correctly initialize the hardware descriptor.
* Note that before calling this function the skb->cb array must be untouched
* by rt2x00lib. Only after this function completes will it be save to
* overwrite the skb->cb information.
* The reason for this is that mac80211 writes its own tx information into
* the skb->cb array, and this function will use that information to initialize
* the &struct txentry_desc structure.
*/
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc);
/**
* rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
* @entry: The entry which will be used to transfer the TX frame.
* @txdesc: TX descriptor which will be used to write hardware descriptor
*
* This function will write a TX descriptor initialized by
* &rt2x00queue_create_tx_descriptor to the hardware. After this call
* has completed the frame is now owned by the hardware, the hardware
* queue will have automatically be kicked unless this frame was generated
* by rt2x00lib, in which case the frame is "special" and must be kicked
* by the caller.
*/
void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc);
/** /**
* rt2x00queue_get_queue - Convert queue index to queue pointer * rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev. * @rt2x00dev: Pointer to &struct rt2x00_dev.
@ -963,18 +995,10 @@ void rt2x00lib_txdone(struct queue_entry *entry,
void rt2x00lib_rxdone(struct queue_entry *entry, void rt2x00lib_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc); struct rxdone_entry_desc *rxdesc);
/*
* TX descriptor initializer
*/
void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct ieee80211_tx_control *control);
/* /*
* mac80211 handlers. * mac80211 handlers.
*/ */
int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
struct ieee80211_tx_control *control);
int rt2x00mac_start(struct ieee80211_hw *hw); int rt2x00mac_start(struct ieee80211_hw *hw);
void rt2x00mac_stop(struct ieee80211_hw *hw); void rt2x00mac_stop(struct ieee80211_hw *hw);
int rt2x00mac_add_interface(struct ieee80211_hw *hw, int rt2x00mac_add_interface(struct ieee80211_hw *hw,

View File

@ -115,7 +115,7 @@ struct rt2x00debug_intf {
}; };
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb) enum rt2x00_dump_type type, struct sk_buff *skb)
{ {
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
struct skb_frame_desc *desc = get_skb_frame_desc(skb); struct skb_frame_desc *desc = get_skb_frame_desc(skb);
@ -148,7 +148,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
dump_hdr->type = cpu_to_le16(desc->frame_type); dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = desc->entry->queue->qid; dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx; dump_hdr->entry_index = desc->entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);

View File

@ -28,7 +28,6 @@
#include "rt2x00.h" #include "rt2x00.h"
#include "rt2x00lib.h" #include "rt2x00lib.h"
#include "rt2x00dump.h"
/* /*
* Link tuning handlers * Link tuning handlers
@ -126,7 +125,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
/* /*
* Start the TX queues. * Start the TX queues.
*/ */
ieee80211_start_queues(rt2x00dev->hw); ieee80211_wake_queues(rt2x00dev->hw);
return 0; return 0;
} }
@ -416,7 +415,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
struct rt2x00_dev *rt2x00dev = data; struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif); struct rt2x00_intf *intf = vif_to_intf(vif);
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_control control;
struct ieee80211_bss_conf conf; struct ieee80211_bss_conf conf;
int delayed_flags; int delayed_flags;
@ -434,9 +432,9 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
spin_unlock(&intf->lock); spin_unlock(&intf->lock);
if (delayed_flags & DELAYED_UPDATE_BEACON) { if (delayed_flags & DELAYED_UPDATE_BEACON) {
skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, if (skb &&
skb, &control)) rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
@ -495,61 +493,55 @@ void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc) struct txdone_entry_desc *txdesc)
{ {
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_tx_status tx_status;
int success = !!(txdesc->status == TX_SUCCESS || /*
txdesc->status == TX_SUCCESS_RETRY); * Send frame to debugfs immediately, after this call is completed
int fail = !!(txdesc->status == TX_FAIL_RETRY || * we are going to overwrite the skb->cb array.
txdesc->status == TX_FAIL_INVALID || */
txdesc->status == TX_FAIL_OTHER); rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
/* /*
* Update TX statistics. * Update TX statistics.
*/ */
rt2x00dev->link.qual.tx_success += success; rt2x00dev->link.qual.tx_success +=
rt2x00dev->link.qual.tx_failed += txdesc->retry + fail; test_bit(TXDONE_SUCCESS, &txdesc->flags);
rt2x00dev->link.qual.tx_failed +=
txdesc->retry + !!test_bit(TXDONE_FAILURE, &txdesc->flags);
/* /*
* Initialize TX status * Initialize TX status
*/ */
tx_status.flags = 0; memset(&tx_info->status, 0, sizeof(tx_info->status));
tx_status.ack_signal = 0; tx_info->status.ack_signal = 0;
tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY); tx_info->status.excessive_retries =
tx_status.retry_count = txdesc->retry; test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control)); tx_info->status.retry_count = txdesc->retry;
if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) { if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (success) if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
tx_status.flags |= IEEE80211_TX_STATUS_ACK; tx_info->flags |= IEEE80211_TX_STAT_ACK;
else else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
rt2x00dev->low_level_stats.dot11ACKFailureCount++; rt2x00dev->low_level_stats.dot11ACKFailureCount++;
} }
if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
if (success) if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
rt2x00dev->low_level_stats.dot11RTSSuccessCount++; rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
else else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
rt2x00dev->low_level_stats.dot11RTSFailureCount++; rt2x00dev->low_level_stats.dot11RTSFailureCount++;
} }
/* /*
* Send the tx_status to debugfs. Only send the status report * Only send the status report to mac80211 when TX status was
* to mac80211 when the frame originated from there. If this was * requested by it. If this was a extra frame coming through
* a extra frame coming through a mac80211 library call (RTS/CTS) * a mac80211 library call (RTS/CTS) then we should not send the
* then we should not send the status report back. * status report back.
* If send to mac80211, mac80211 will clean up the skb structure,
* otherwise we have to do it ourself.
*/ */
skbdesc = get_skb_frame_desc(entry->skb); if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
skbdesc->frame_type = DUMP_FRAME_TXDONE; ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
rt2x00debug_dump_frame(rt2x00dev, entry->skb);
if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
ieee80211_tx_status_irqsafe(rt2x00dev->hw,
entry->skb, &tx_status);
else else
dev_kfree_skb(entry->skb); dev_kfree_skb_irq(entry->skb);
entry->skb = NULL; entry->skb = NULL;
} }
EXPORT_SYMBOL_GPL(rt2x00lib_txdone); EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@ -610,153 +602,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
* Send frame to mac80211 & debugfs. * Send frame to mac80211 & debugfs.
* mac80211 will clean up the skb structure. * mac80211 will clean up the skb structure.
*/ */
get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE; rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
rt2x00debug_dump_frame(rt2x00dev, entry->skb);
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
entry->skb = NULL; entry->skb = NULL;
} }
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
/*
* TX descriptor initializer
*/
void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
struct ieee80211_tx_control *control)
{
struct txentry_desc txdesc;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data;
const struct rt2x00_rate *rate;
int tx_rate;
int length;
int duration;
int residual;
u16 frame_control;
u16 seq_ctrl;
memset(&txdesc, 0, sizeof(txdesc));
txdesc.queue = skbdesc->entry->queue->qid;
txdesc.cw_min = skbdesc->entry->queue->cw_min;
txdesc.cw_max = skbdesc->entry->queue->cw_max;
txdesc.aifs = skbdesc->entry->queue->aifs;
/*
* Read required fields from ieee80211 header.
*/
frame_control = le16_to_cpu(hdr->frame_control);
seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
tx_rate = control->tx_rate->hw_value;
/*
* Check whether this frame is to be acked
*/
if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
__set_bit(ENTRY_TXD_ACK, &txdesc.flags);
/*
* Check if this is a RTS/CTS frame
*/
if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
__set_bit(ENTRY_TXD_BURST, &txdesc.flags);
if (is_rts_frame(frame_control)) {
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags);
__set_bit(ENTRY_TXD_ACK, &txdesc.flags);
} else
__clear_bit(ENTRY_TXD_ACK, &txdesc.flags);
if (control->rts_cts_rate)
tx_rate = control->rts_cts_rate->hw_value;
}
rate = rt2x00_get_rate(tx_rate);
/*
* Check if more fragments are pending
*/
if (ieee80211_get_morefrag(hdr)) {
__set_bit(ENTRY_TXD_BURST, &txdesc.flags);
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags);
}
/*
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame.
*/
if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control))
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);
/*
* Determine with what IFS priority this frame should be send.
* Set ifs to IFS_SIFS when the this is not the first fragment,
* or this fragment came after RTS/CTS.
*/
if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags))
txdesc.ifs = IFS_SIFS;
else
txdesc.ifs = IFS_BACKOFF;
/*
* PLCP setup
* Length calculation depends on OFDM/CCK rate.
*/
txdesc.signal = rate->plcp;
txdesc.service = 0x04;
length = skbdesc->data_len + FCS_LEN;
if (rate->flags & DEV_RATE_OFDM) {
__set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags);
txdesc.length_high = (length >> 6) & 0x3f;
txdesc.length_low = length & 0x3f;
} else {
/*
* Convert length to microseconds.
*/
residual = get_duration_res(length, rate->bitrate);
duration = get_duration(length, rate->bitrate);
if (residual != 0) {
duration++;
/*
* Check if we need to set the Length Extension
*/
if (rate->bitrate == 110 && residual <= 30)
txdesc.service |= 0x80;
}
txdesc.length_high = (duration >> 8) & 0xff;
txdesc.length_low = duration & 0xff;
/*
* When preamble is enabled we should set the
* preamble bit for the signal.
*/
if (rt2x00_get_rate_preamble(tx_rate))
txdesc.signal |= 0x08;
}
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control);
/*
* Update queue entry.
*/
skbdesc->entry->skb = skb;
/*
* The frame has been completely initialized and ready
* for sending to the device. The caller will push the
* frame to the device, but we are going to push the
* frame to debugfs here.
*/
skbdesc->frame_type = DUMP_FRAME_TX;
rt2x00debug_dump_frame(rt2x00dev, skb);
}
EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
/* /*
* Driver initialization handlers. * Driver initialization handlers.
*/ */
@ -972,6 +823,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
if (status) if (status)
return status; return status;
/*
* Initialize HW fields.
*/
rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues;
/* /*
* Register HW. * Register HW.
*/ */
@ -1327,7 +1183,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
* In that case we have disabled the TX queue and should * In that case we have disabled the TX queue and should
* now enable it again * now enable it again
*/ */
ieee80211_start_queues(rt2x00dev->hw); ieee80211_wake_queues(rt2x00dev->hw);
/* /*
* During interface iteration we might have changed the * During interface iteration we might have changed the

View File

@ -26,6 +26,8 @@
#ifndef RT2X00LIB_H #ifndef RT2X00LIB_H
#define RT2X00LIB_H #define RT2X00LIB_H
#include "rt2x00dump.h"
/* /*
* Interval defines * Interval defines
* Both the link tuner as the rfkill will be called once per second. * Both the link tuner as the rfkill will be called once per second.
@ -128,7 +130,8 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
#ifdef CONFIG_RT2X00_LIB_DEBUGFS #ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type, struct sk_buff *skb);
#else #else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{ {
@ -139,6 +142,7 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
} }
static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
enum rt2x00_dump_type type,
struct sk_buff *skb) struct sk_buff *skb)
{ {
} }

View File

@ -31,14 +31,15 @@
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct data_queue *queue,
struct sk_buff *frag_skb, struct sk_buff *frag_skb)
struct ieee80211_tx_control *control)
{ {
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct ieee80211_tx_info *rts_info;
struct sk_buff *skb; struct sk_buff *skb;
int size; int size;
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
size = sizeof(struct ieee80211_cts); size = sizeof(struct ieee80211_cts);
else else
size = sizeof(struct ieee80211_rts); size = sizeof(struct ieee80211_rts);
@ -52,13 +53,33 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
skb_put(skb, size); skb_put(skb, size);
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) /*
ieee80211_ctstoself_get(rt2x00dev->hw, control->vif, * Copy TX information over from original frame to
frag_skb->data, frag_skb->len, control, * RTS/CTS frame. Note that we set the no encryption flag
* since we don't want this frame to be encrypted.
* RTS frames should be acked, while CTS-to-self frames
* should not. The ready for TX flag is cleared to prevent
* it being automatically send when the descriptor is
* written to the hardware.
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, size, tx_info,
(struct ieee80211_cts *)(skb->data)); (struct ieee80211_cts *)(skb->data));
else else
ieee80211_rts_get(rt2x00dev->hw, control->vif, ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
frag_skb->data, frag_skb->len, control, frag_skb->data, size, tx_info,
(struct ieee80211_rts *)(skb->data)); (struct ieee80211_rts *)(skb->data));
/* /*
@ -68,7 +89,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
memset(skbdesc, 0, sizeof(*skbdesc)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n"); WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
@ -76,14 +97,13 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); enum data_queue_qid qid = skb_get_queue_mapping(skb);
struct data_queue *queue; struct data_queue *queue;
struct skb_frame_desc *skbdesc;
u16 frame_control; u16 frame_control;
/* /*
@ -100,7 +120,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
/* /*
* Determine which queue to put packet on. * Determine which queue to put packet on.
*/ */
if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM && if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM);
else else
@ -125,33 +145,27 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
*/ */
frame_control = le16_to_cpu(ieee80211hdr->frame_control); frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
(control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | (tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
IEEE80211_TXCTL_USE_CTS_PROTECT)) && IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
!rt2x00dev->ops->hw->set_rts_threshold) { !rt2x00dev->ops->hw->set_rts_threshold) {
if (rt2x00queue_available(queue) <= 1) { if (rt2x00queue_available(queue) <= 1) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue); ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue); ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
} }
/* if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
* Initialize skb descriptor ieee80211_stop_queue(rt2x00dev->hw, qid);
*/
skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
ieee80211_stop_queue(rt2x00dev->hw, control->queue);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
if (rt2x00queue_full(queue)) if (rt2x00queue_full(queue))
ieee80211_stop_queue(rt2x00dev->hw, control->queue); ieee80211_stop_queue(rt2x00dev->hw, qid);
if (rt2x00dev->ops->lib->kick_tx_queue) if (rt2x00dev->ops->lib->kick_tx_queue)
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid);
@ -380,9 +394,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon) if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
return 0; return 0;
status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
conf->beacon,
conf->beacon_control);
if (status) if (status)
dev_kfree_skb(conf->beacon); dev_kfree_skb(conf->beacon);
@ -456,7 +468,7 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i; unsigned int i;
for (i = 0; i < hw->queues; i++) { for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
stats[i].len = rt2x00dev->tx[i].length; stats[i].len = rt2x00dev->tx[i].length;
stats[i].limit = rt2x00dev->tx[i].limit; stats[i].limit = rt2x00dev->tx[i].limit;
stats[i].count = rt2x00dev->tx[i].count; stats[i].count = rt2x00dev->tx[i].count;

View File

@ -35,18 +35,18 @@
* TX data handlers. * TX data handlers.
*/ */
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct sk_buff *skb, struct data_queue *queue, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
u32 word; u32 word;
if (rt2x00queue_full(queue)) if (rt2x00queue_full(queue))
return -EINVAL; return -EINVAL;
rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
rt2x00_get_field32(word, TXD_ENTRY_VALID)) { rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
@ -57,20 +57,28 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
return -EINVAL; return -EINVAL;
} }
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
entry->skb = skb;
rt2x00queue_create_tx_descriptor(entry, &txdesc);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
*/ */
skbdesc = get_skb_frame_desc(skb); skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data; skbdesc->data = skb->data;
skbdesc->data_len = skb->len; skbdesc->data_len = skb->len;
skbdesc->desc = priv_tx->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry; skbdesc->entry = entry;
memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); memcpy(entry_priv->data, skb->data, skb->len);
memcpy(priv_tx->data, skb->data, skb->len);
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_index_inc(queue, Q_INDEX);
return 0; return 0;
@ -84,7 +92,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{ {
struct data_queue *queue = rt2x00dev->rx; struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry; struct queue_entry *entry;
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc; struct rxdone_entry_desc rxdesc;
@ -94,8 +102,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
while (1) { while (1) {
entry = rt2x00queue_get_entry(queue, Q_INDEX); entry = rt2x00queue_get_entry(queue, Q_INDEX);
priv_rx = entry->priv_data; entry_priv = entry->priv_data;
rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
break; break;
@ -103,7 +111,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
memset(&rxdesc, 0, sizeof(rxdesc)); memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
hdr = (struct ieee80211_hdr *)priv_rx->data; hdr = (struct ieee80211_hdr *)entry_priv->data;
header_size = header_size =
ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
@ -123,7 +131,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
skb_reserve(entry->skb, align); skb_reserve(entry->skb, align);
memcpy(skb_put(entry->skb, rxdesc.size), memcpy(skb_put(entry->skb, rxdesc.size),
priv_rx->data, rxdesc.size); entry_priv->data, rxdesc.size);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
@ -132,7 +140,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
memset(skbdesc, 0, sizeof(*skbdesc)); memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = entry->skb->data; skbdesc->data = entry->skb->data;
skbdesc->data_len = entry->skb->len; skbdesc->data_len = entry->skb->len;
skbdesc->desc = priv_rx->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry; skbdesc->entry = entry;
@ -143,7 +151,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) { if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
rt2x00_desc_write(priv_rx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_index_inc(queue, Q_INDEX);
@ -154,10 +162,10 @@ EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry, void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
struct txdone_entry_desc *txdesc) struct txdone_entry_desc *txdesc)
{ {
struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word; u32 word;
txdesc->control = &priv_tx->control;
rt2x00lib_txdone(entry, txdesc); rt2x00lib_txdone(entry, txdesc);
/* /*
@ -165,10 +173,10 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
*/ */
entry->flags = 0; entry->flags = 0;
rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
rt2x00_desc_write(priv_tx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
@ -178,7 +186,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
* is reenabled when the txdone handler has finished. * is reenabled when the txdone handler has finished.
*/ */
if (!rt2x00queue_full(entry->queue)) if (!rt2x00queue_full(entry->queue))
ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); ieee80211_wake_queue(rt2x00dev->hw, qid);
} }
EXPORT_SYMBOL_GPL(rt2x00pci_txdone); EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
@ -217,14 +225,9 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry_priv_pci_tx *priv_tx;
void *addr; void *addr;
dma_addr_t dma; dma_addr_t dma;
void *desc_addr;
dma_addr_t desc_dma;
void *data_addr;
dma_addr_t data_dma;
unsigned int i; unsigned int i;
/* /*
@ -240,24 +243,11 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
* Initialize all queue entries to contain valid addresses. * Initialize all queue entries to contain valid addresses.
*/ */
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
desc_addr = desc_offset(queue, addr, i); entry_priv = queue->entries[i].priv_data;
desc_dma = desc_offset(queue, dma, i); entry_priv->desc = desc_offset(queue, addr, i);
data_addr = data_offset(queue, addr, i); entry_priv->desc_dma = desc_offset(queue, dma, i);
data_dma = data_offset(queue, dma, i); entry_priv->data = data_offset(queue, addr, i);
entry_priv->data_dma = data_offset(queue, dma, i);
if (queue->qid == QID_RX) {
priv_rx = queue->entries[i].priv_data;
priv_rx->desc = desc_addr;
priv_rx->desc_dma = desc_dma;
priv_rx->data = data_addr;
priv_rx->data_dma = data_dma;
} else {
priv_tx = queue->entries[i].priv_data;
priv_tx->desc = desc_addr;
priv_tx->desc_dma = desc_dma;
priv_tx->data = data_addr;
priv_tx->data_dma = data_dma;
}
} }
return 0; return 0;
@ -267,28 +257,13 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev); struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv =
struct queue_entry_priv_pci_tx *priv_tx; queue->entries[0].priv_data;
void *data_addr;
dma_addr_t data_dma;
if (queue->qid == QID_RX) { if (entry_priv->data)
priv_rx = queue->entries[0].priv_data;
data_addr = priv_rx->data;
data_dma = priv_rx->data_dma;
priv_rx->data = NULL;
} else {
priv_tx = queue->entries[0].priv_data;
data_addr = priv_tx->data;
data_dma = priv_tx->data_dma;
priv_tx->data = NULL;
}
if (data_addr)
pci_free_consistent(pci_dev, dma_size(queue), pci_free_consistent(pci_dev, dma_size(queue),
data_addr, data_dma); entry_priv->data, entry_priv->data_dma);
entry_priv->data = NULL;
} }
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)

View File

@ -91,42 +91,22 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
* TX data handlers. * TX data handlers.
*/ */
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct sk_buff *skb, struct data_queue *queue, struct sk_buff *skb);
struct ieee80211_tx_control *control);
/** /**
* struct queue_entry_priv_pci_rx: Per RX entry PCI specific information * struct queue_entry_priv_pci: Per entry PCI specific information
*
* @desc: Pointer to device descriptor.
* @desc_dma: DMA pointer to @desc.
* @data: Pointer to device's entry memory.
* @data_dma: DMA pointer to &data.
*/
struct queue_entry_priv_pci_rx {
__le32 *desc;
dma_addr_t desc_dma;
void *data;
dma_addr_t data_dma;
};
/**
* struct queue_entry_priv_pci_tx: Per TX entry PCI specific information
* *
* @desc: Pointer to device descriptor * @desc: Pointer to device descriptor
* @desc_dma: DMA pointer to @desc. * @desc_dma: DMA pointer to &desc.
* @data: Pointer to device's entry memory. * @data: Pointer to device's entry memory.
* @data_dma: DMA pointer to &data. * @data_dma: DMA pointer to &data.
* @control: mac80211 control structure used to transmit data.
*/ */
struct queue_entry_priv_pci_tx { struct queue_entry_priv_pci {
__le32 *desc; __le32 *desc;
dma_addr_t desc_dma; dma_addr_t desc_dma;
void *data; void *data;
dma_addr_t data_dma; dma_addr_t data_dma;
struct ieee80211_tx_control control;
}; };
/** /**

View File

@ -29,12 +29,171 @@
#include "rt2x00.h" #include "rt2x00.h"
#include "rt2x00lib.h" #include "rt2x00lib.h"
void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct ieee80211_rate *rate =
ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
const struct rt2x00_rate *hwrate;
unsigned int data_length;
unsigned int duration;
unsigned int residual;
u16 frame_control;
memset(txdesc, 0, sizeof(*txdesc));
/*
* Initialize information from queue
*/
txdesc->queue = entry->queue->qid;
txdesc->cw_min = entry->queue->cw_min;
txdesc->cw_max = entry->queue->cw_max;
txdesc->aifs = entry->queue->aifs;
/* Data length should be extended with 4 bytes for CRC */
data_length = entry->skb->len + 4;
/*
* Read required fields from ieee80211 header.
*/
frame_control = le16_to_cpu(hdr->frame_control);
/*
* Check whether this frame is to be acked.
*/
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
/*
* Check if this is a RTS/CTS frame
*/
if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
if (is_rts_frame(frame_control))
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
else
__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
if (tx_info->control.rts_cts_rate_idx >= 0)
rate =
ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
}
/*
* Determine retry information.
*/
txdesc->retry_limit = tx_info->control.retry_limit;
if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
/*
* Check if more fragments are pending
*/
if (ieee80211_get_morefrag(hdr)) {
__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
}
/*
* Beacons and probe responses require the tsf timestamp
* to be inserted into the frame.
*/
if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control))
__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
/*
* Determine with what IFS priority this frame should be send.
* Set ifs to IFS_SIFS when the this is not the first fragment,
* or this fragment came after RTS/CTS.
*/
if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) {
txdesc->ifs = IFS_SIFS;
} else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
__set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags);
txdesc->ifs = IFS_BACKOFF;
} else {
txdesc->ifs = IFS_SIFS;
}
/*
* PLCP setup
* Length calculation depends on OFDM/CCK rate.
*/
hwrate = rt2x00_get_rate(rate->hw_value);
txdesc->signal = hwrate->plcp;
txdesc->service = 0x04;
if (hwrate->flags & DEV_RATE_OFDM) {
__set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags);
txdesc->length_high = (data_length >> 6) & 0x3f;
txdesc->length_low = data_length & 0x3f;
} else {
/*
* Convert length to microseconds.
*/
residual = get_duration_res(data_length, hwrate->bitrate);
duration = get_duration(data_length, hwrate->bitrate);
if (residual != 0) {
duration++;
/*
* Check if we need to set the Length Extension
*/
if (hwrate->bitrate == 110 && residual <= 30)
txdesc->service |= 0x80;
}
txdesc->length_high = (duration >> 8) & 0xff;
txdesc->length_low = duration & 0xff;
/*
* When preamble is enabled we should set the
* preamble bit for the signal.
*/
if (rt2x00_get_rate_preamble(rate->hw_value))
txdesc->signal |= 0x08;
}
}
EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
/*
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
/*
* We are done writing the frame to the queue entry,
* also kick the queue in case the correct flags are set,
* note that this will automatically filter beacons and
* RTS/CTS frames since those frames don't have this flag
* set.
*/
if (rt2x00dev->ops->lib->kick_tx_queue &&
!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev,
entry->queue->qid);
}
EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue) const enum data_queue_qid queue)
{ {
int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx)
return &rt2x00dev->tx[queue]; return &rt2x00dev->tx[queue];
if (!rt2x00dev->bcn) if (!rt2x00dev->bcn)
@ -255,11 +414,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
/* /*
* We need the following queues: * We need the following queues:
* RX: 1 * RX: 1
* TX: hw->queues * TX: ops->tx_queues
* Beacon: 1 * Beacon: 1
* Atim: 1 (if required) * Atim: 1 (if required)
*/ */
rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim; rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL); queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
if (!queue) { if (!queue) {
@ -272,7 +431,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/ */
rt2x00dev->rx = queue; rt2x00dev->rx = queue;
rt2x00dev->tx = &queue[1]; rt2x00dev->tx = &queue[1];
rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues]; rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
/* /*
* Initialize queue parameters. * Initialize queue parameters.

View File

@ -79,19 +79,6 @@ enum data_queue_qid {
QID_ATIM, QID_ATIM,
}; };
/**
* mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid
* @queue: mac80211 queue.
*/
static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue)
{
/* Regular TX queues are mapped directly */
if (queue < 4)
return queue;
WARN_ON(1);
return QID_OTHER;
}
/** /**
* enum skb_frame_desc_flags: Flags for &struct skb_frame_desc * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
* *
@ -105,11 +92,10 @@ enum skb_frame_desc_flags {
/** /**
* struct skb_frame_desc: Descriptor information for the skb buffer * struct skb_frame_desc: Descriptor information for the skb buffer
* *
* This structure is placed over the skb->cb array, this means that * This structure is placed over the driver_data array, this means that
* this structure should not exceed the size of that array (48 bytes). * this structure should not exceed the size of that array (40 bytes).
* *
* @flags: Frame flags, see &enum skb_frame_desc_flags. * @flags: Frame flags, see &enum skb_frame_desc_flags.
* @frame_type: Frame type, see &enum rt2x00_dump_type.
* @data: Pointer to data part of frame (Start of ieee80211 header). * @data: Pointer to data part of frame (Start of ieee80211 header).
* @desc: Pointer to descriptor part of the frame. * @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside * Note that this pointer could point to something outside
@ -121,21 +107,24 @@ enum skb_frame_desc_flags {
struct skb_frame_desc { struct skb_frame_desc {
unsigned int flags; unsigned int flags;
unsigned int frame_type; unsigned short data_len;
unsigned short desc_len;
void *data; void *data;
void *desc; void *desc;
unsigned int data_len;
unsigned int desc_len;
struct queue_entry *entry; struct queue_entry *entry;
}; };
/**
* get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff.
* @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc
*/
static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
{ {
BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(struct skb_frame_desc) >
return (struct skb_frame_desc *)&skb->cb[0]; IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data;
} }
/** /**
@ -170,19 +159,33 @@ struct rxdone_entry_desc {
int dev_flags; int dev_flags;
}; };
/**
* enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
*
* @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
* @TXDONE_SUCCESS: Frame was successfully send
* @TXDONE_FAILURE: Frame was not successfully send
* @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
* frame transmission failed due to excessive retries.
*/
enum txdone_entry_desc_flags {
TXDONE_UNKNOWN = 1 << 0,
TXDONE_SUCCESS = 1 << 1,
TXDONE_FAILURE = 1 << 2,
TXDONE_EXCESSIVE_RETRY = 1 << 3,
};
/** /**
* struct txdone_entry_desc: TX done entry descriptor * struct txdone_entry_desc: TX done entry descriptor
* *
* Summary of information that has been read from the TX frame descriptor * Summary of information that has been read from the TX frame descriptor
* after the device is done with transmission. * after the device is done with transmission.
* *
* @control: Control structure which was used to transmit the frame. * @flags: TX done flags (See &enum txdone_entry_desc_flags).
* @status: TX status (See &enum tx_status).
* @retry: Retry count. * @retry: Retry count.
*/ */
struct txdone_entry_desc { struct txdone_entry_desc {
struct ieee80211_tx_control *control; unsigned long flags;
int status;
int retry; int retry;
}; };
@ -190,19 +193,25 @@ struct txdone_entry_desc {
* enum txentry_desc_flags: Status flags for TX entry descriptor * enum txentry_desc_flags: Status flags for TX entry descriptor
* *
* @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame. * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
* @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
* @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate. * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
* @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
* @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment. * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
* @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted. * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
* @ENTRY_TXD_BURST: This frame belongs to the same burst event. * @ENTRY_TXD_BURST: This frame belongs to the same burst event.
* @ENTRY_TXD_ACK: An ACK is required for this frame. * @ENTRY_TXD_ACK: An ACK is required for this frame.
* @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
*/ */
enum txentry_desc_flags { enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME, ENTRY_TXD_RTS_FRAME,
ENTRY_TXD_CTS_FRAME,
ENTRY_TXD_OFDM_RATE, ENTRY_TXD_OFDM_RATE,
ENTRY_TXD_FIRST_FRAGMENT,
ENTRY_TXD_MORE_FRAG, ENTRY_TXD_MORE_FRAG,
ENTRY_TXD_REQ_TIMESTAMP, ENTRY_TXD_REQ_TIMESTAMP,
ENTRY_TXD_BURST, ENTRY_TXD_BURST,
ENTRY_TXD_ACK, ENTRY_TXD_ACK,
ENTRY_TXD_RETRY_MODE,
}; };
/** /**
@ -216,6 +225,7 @@ enum txentry_desc_flags {
* @length_low: PLCP length low word. * @length_low: PLCP length low word.
* @signal: PLCP signal. * @signal: PLCP signal.
* @service: PLCP service. * @service: PLCP service.
* @retry_limit: Max number of retries.
* @aifs: AIFS value. * @aifs: AIFS value.
* @ifs: IFS value. * @ifs: IFS value.
* @cw_min: cwmin value. * @cw_min: cwmin value.
@ -231,10 +241,11 @@ struct txentry_desc {
u16 signal; u16 signal;
u16 service; u16 service;
int aifs; short retry_limit;
int ifs; short aifs;
int cw_min; short ifs;
int cw_max; short cw_min;
short cw_max;
}; };
/** /**
@ -378,7 +389,7 @@ struct data_queue_desc {
* the end of the TX queue array. * the end of the TX queue array.
*/ */
#define tx_queue_end(__dev) \ #define tx_queue_end(__dev) \
&(__dev)->tx[(__dev)->hw->queues] &(__dev)->tx[(__dev)->ops->tx_queues]
/** /**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO). * queue_loop - Loop through the queues within a specific range (HELPER MACRO).

View File

@ -26,17 +26,6 @@
#ifndef RT2X00REG_H #ifndef RT2X00REG_H
#define RT2X00REG_H #define RT2X00REG_H
/*
* TX result flags.
*/
enum tx_status {
TX_SUCCESS = 0,
TX_SUCCESS_RETRY = 1,
TX_FAIL_RETRY = 2,
TX_FAIL_INVALID = 3,
TX_FAIL_OTHER = 4,
};
/* /*
* Antenna values * Antenna values
*/ */

View File

@ -129,9 +129,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
{ {
struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
struct txdone_entry_desc txdesc; struct txdone_entry_desc txdesc;
__le32 *txd = (__le32 *)entry->skb->data; __le32 *txd = (__le32 *)entry->skb->data;
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word; u32 word;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
@ -147,10 +147,18 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
/* /*
* Obtain the status about this packet. * Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
* frame was send out correctly. It only means the frame
* was succesfully pushed to the hardware, we have no
* way to determine the transmission status right now.
* (Only indirectly by looking at the failed TX counters
* in the register).
*/ */
txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY; if (!urb->status)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
else
__set_bit(TXDONE_FAILURE, &txdesc.flags);
txdesc.retry = 0; txdesc.retry = 0;
txdesc.control = &priv_tx->control;
rt2x00lib_txdone(entry, &txdesc); rt2x00lib_txdone(entry, &txdesc);
@ -166,17 +174,17 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* is reenabled when the txdone handler has finished. * is reenabled when the txdone handler has finished.
*/ */
if (!rt2x00queue_full(entry->queue)) if (!rt2x00queue_full(entry->queue))
ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); ieee80211_wake_queue(rt2x00dev->hw, qid);
} }
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct sk_buff *skb, struct data_queue *queue, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data; struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
u32 length; u32 length;
if (rt2x00queue_full(queue)) if (rt2x00queue_full(queue))
@ -190,6 +198,14 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
return -EINVAL; return -EINVAL;
} }
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
entry->skb = skb;
rt2x00queue_create_tx_descriptor(entry, &txdesc);
/* /*
* Add the descriptor in front of the skb. * Add the descriptor in front of the skb.
*/ */
@ -200,14 +216,14 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
* Fill in skb descriptor * Fill in skb descriptor
*/ */
skbdesc = get_skb_frame_desc(skb); skbdesc = get_skb_frame_desc(skb);
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data + queue->desc_size; skbdesc->data = skb->data + queue->desc_size;
skbdesc->data_len = skb->len - queue->desc_size; skbdesc->data_len = skb->len - queue->desc_size;
skbdesc->desc = skb->data; skbdesc->desc = skb->data;
skbdesc->desc_len = queue->desc_size; skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry; skbdesc->entry = entry;
memcpy(&priv_tx->control, control, sizeof(priv_tx->control)); rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
/* /*
* USB devices cannot blindly pass the skb->len as the * USB devices cannot blindly pass the skb->len as the
@ -220,9 +236,9 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
* Initialize URB and send the frame to the device. * Initialize URB and send the frame to the device.
*/ */
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1), usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
skb->data, length, rt2x00usb_interrupt_txdone, entry); skb->data, length, rt2x00usb_interrupt_txdone, entry);
usb_submit_urb(priv_tx->urb, GFP_ATOMIC); usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_index_inc(queue, Q_INDEX);
@ -237,22 +253,35 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned int frame_size; unsigned int frame_size;
unsigned int reserved_size;
/* /*
* As alignment we use 2 and not NET_IP_ALIGN because we need * The frame size includes descriptor size, because the
* to be sure we have 2 bytes room in the head. (NET_IP_ALIGN * hardware directly receive the frame into the skbuffer.
* can be 0 on some hardware). We use these 2 bytes for frame
* alignment later, we assume that the chance that
* header_size % 4 == 2 is bigger then header_size % 2 == 0
* and thus optimize alignment by reserving the 2 bytes in
* advance.
*/ */
frame_size = queue->data_size + queue->desc_size; frame_size = queue->data_size + queue->desc_size;
skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
/*
* For the allocation we should keep a few things in mind:
* 1) 4byte alignment of 802.11 payload
*
* For (1) we need at most 4 bytes to guarentee the correct
* alignment. We are going to optimize the fact that the chance
* that the 802.11 header_size % 4 == 2 is much bigger then
* anything else. However since we need to move the frame up
* to 3 bytes to the front, which means we need to preallocate
* 6 bytes.
*/
reserved_size = 6;
/*
* Allocate skbuffer.
*/
skb = dev_alloc_skb(frame_size + reserved_size);
if (!skb) if (!skb)
return NULL; return NULL;
skb_reserve(skb, queue->desc_size + 2); skb_reserve(skb, reserved_size);
skb_put(skb, frame_size); skb_put(skb, frame_size);
return skb; return skb;
@ -265,7 +294,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
struct sk_buff *skb; struct sk_buff *skb;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc; struct rxdone_entry_desc rxdesc;
int header_size; unsigned int header_size;
unsigned int align;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
@ -289,19 +319,29 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
memset(&rxdesc, 0, sizeof(rxdesc)); memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
/* /*
* The data behind the ieee80211 header must be * The data behind the ieee80211 header must be
* aligned on a 4 byte boundary. * aligned on a 4 byte boundary. We already reserved
* 2 bytes for header_size % 4 == 2 optimization.
* To determine the number of bytes which the data
* should be moved to the left, we must add these
* 2 bytes to the header_size.
*/ */
header_size = ieee80211_get_hdrlen_from_skb(entry->skb); align = (header_size + 2) % 4;
if (header_size % 4 == 0) {
skb_push(entry->skb, 2); if (align) {
memmove(entry->skb->data, entry->skb->data + 2, skb_push(entry->skb, align);
entry->skb->len - 2); /* Move entire frame in 1 command */
skbdesc->data = entry->skb->data; memmove(entry->skb->data, entry->skb->data + align,
skb_trim(entry->skb,entry->skb->len - 2); rxdesc.size);
} }
/* Update data pointers, trim buffer to correct size */
skbdesc->data = entry->skb->data;
skb_trim(entry->skb, rxdesc.size);
/* /*
* Allocate a new sk buffer to replace the current one. * Allocate a new sk buffer to replace the current one.
* If allocation fails, we should drop the current frame * If allocation fails, we should drop the current frame
@ -338,10 +378,8 @@ skip_entry:
*/ */
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{ {
struct queue_entry_priv_usb_rx *priv_rx; struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_tx *priv_tx; struct queue_entry_priv_usb_bcn *bcn_priv;
struct queue_entry_priv_usb_bcn *priv_bcn;
struct data_queue *queue;
unsigned int i; unsigned int i;
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0, rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
@ -351,31 +389,17 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
* Cancel all queues. * Cancel all queues.
*/ */
for (i = 0; i < rt2x00dev->rx->limit; i++) { for (i = 0; i < rt2x00dev->rx->limit; i++) {
priv_rx = rt2x00dev->rx->entries[i].priv_data; entry_priv = rt2x00dev->rx->entries[i].priv_data;
usb_kill_urb(priv_rx->urb); usb_kill_urb(entry_priv->urb);
}
tx_queue_for_each(rt2x00dev, queue) {
for (i = 0; i < queue->limit; i++) {
priv_tx = queue->entries[i].priv_data;
usb_kill_urb(priv_tx->urb);
}
} }
/*
* Kill guardian urb.
*/
for (i = 0; i < rt2x00dev->bcn->limit; i++) { for (i = 0; i < rt2x00dev->bcn->limit; i++) {
priv_bcn = rt2x00dev->bcn->entries[i].priv_data; bcn_priv = rt2x00dev->bcn->entries[i].priv_data;
usb_kill_urb(priv_bcn->urb); if (bcn_priv->guardian_urb)
usb_kill_urb(bcn_priv->guardian_urb);
if (priv_bcn->guardian_urb)
usb_kill_urb(priv_bcn->guardian_urb);
}
if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
return;
for (i = 0; i < rt2x00dev->bcn[1].limit; i++) {
priv_tx = rt2x00dev->bcn[1].entries[i].priv_data;
usb_kill_urb(priv_tx->urb);
} }
} }
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@ -387,15 +411,15 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev); struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data; struct queue_entry_priv_usb *entry_priv = entry->priv_data;
usb_fill_bulk_urb(priv_rx->urb, usb_dev, usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 1), usb_rcvbulkpipe(usb_dev, 1),
entry->skb->data, entry->skb->len, entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry); rt2x00usb_interrupt_rxdone, entry);
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
usb_submit_urb(priv_rx->urb, GFP_ATOMIC); usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
} }
EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
@ -409,38 +433,31 @@ EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
struct queue_entry_priv_usb_rx *priv_rx; struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_tx *priv_tx; struct queue_entry_priv_usb_bcn *bcn_priv;
struct queue_entry_priv_usb_bcn *priv_bcn;
struct urb *urb;
unsigned int guardian =
test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
unsigned int i; unsigned int i;
/*
* Allocate the URB's
*/
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
urb = usb_alloc_urb(0, GFP_KERNEL); entry_priv = queue->entries[i].priv_data;
if (!urb) entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!entry_priv->urb)
return -ENOMEM; return -ENOMEM;
}
if (queue->qid == QID_RX) { /*
priv_rx = queue->entries[i].priv_data; * If this is not the beacon queue or
priv_rx->urb = urb; * no guardian byte was required for the beacon,
} else if (queue->qid == QID_MGMT && guardian) { * then we are done.
priv_bcn = queue->entries[i].priv_data; */
priv_bcn->urb = urb; if (rt2x00dev->bcn != queue ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return 0;
urb = usb_alloc_urb(0, GFP_KERNEL); for (i = 0; i < queue->limit; i++) {
if (!urb) bcn_priv = queue->entries[i].priv_data;
return -ENOMEM; bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!bcn_priv->guardian_urb)
priv_bcn->guardian_urb = urb; return -ENOMEM;
} else {
priv_tx = queue->entries[i].priv_data;
priv_tx->urb = urb;
}
} }
return 0; return 0;
@ -449,38 +466,35 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev, static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue) struct data_queue *queue)
{ {
struct queue_entry_priv_usb_rx *priv_rx; struct queue_entry_priv_usb *entry_priv;
struct queue_entry_priv_usb_tx *priv_tx; struct queue_entry_priv_usb_bcn *bcn_priv;
struct queue_entry_priv_usb_bcn *priv_bcn;
struct urb *urb;
unsigned int guardian =
test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
unsigned int i; unsigned int i;
if (!queue->entries) if (!queue->entries)
return; return;
for (i = 0; i < queue->limit; i++) { for (i = 0; i < queue->limit; i++) {
if (queue->qid == QID_RX) { entry_priv = queue->entries[i].priv_data;
priv_rx = queue->entries[i].priv_data; usb_kill_urb(entry_priv->urb);
urb = priv_rx->urb; usb_free_urb(entry_priv->urb);
} else if (queue->qid == QID_MGMT && guardian) {
priv_bcn = queue->entries[i].priv_data;
usb_kill_urb(priv_bcn->guardian_urb);
usb_free_urb(priv_bcn->guardian_urb);
urb = priv_bcn->urb;
} else {
priv_tx = queue->entries[i].priv_data;
urb = priv_tx->urb;
}
usb_kill_urb(urb);
usb_free_urb(urb);
if (queue->entries[i].skb) if (queue->entries[i].skb)
kfree_skb(queue->entries[i].skb); kfree_skb(queue->entries[i].skb);
} }
/*
* If this is not the beacon queue or
* no guardian byte was required for the beacon,
* then we are done.
*/
if (rt2x00dev->bcn != queue ||
!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
return;
for (i = 0; i < queue->limit; i++) {
bcn_priv = queue->entries[i].priv_data;
usb_kill_urb(bcn_priv->guardian_urb);
usb_free_urb(bcn_priv->guardian_urb);
}
} }
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)

View File

@ -216,47 +216,31 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
* TX data handlers. * TX data handlers.
*/ */
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, struct sk_buff *skb, struct data_queue *queue, struct sk_buff *skb);
struct ieee80211_tx_control *control);
/** /**
* struct queue_entry_priv_usb_rx: Per RX entry USB specific information * struct queue_entry_priv_usb: Per entry USB specific information
* *
* @urb: Urb structure used for device communication. * @urb: Urb structure used for device communication.
*/ */
struct queue_entry_priv_usb_rx { struct queue_entry_priv_usb {
struct urb *urb; struct urb *urb;
}; };
/** /**
* struct queue_entry_priv_usb_tx: Per TX entry USB specific information * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information
* *
* @urb: Urb structure used for device communication. * The first section should match &struct queue_entry_priv_usb exactly.
* @control: mac80211 control structure used to transmit data.
*/
struct queue_entry_priv_usb_tx {
struct urb *urb;
struct ieee80211_tx_control control;
};
/**
* struct queue_entry_priv_usb_tx: Per TX entry USB specific information
*
* The first section should match &struct queue_entry_priv_usb_tx exactly.
* rt2500usb can use this structure to send a guardian byte when working * rt2500usb can use this structure to send a guardian byte when working
* with beacons. * with beacons.
* *
* @urb: Urb structure used for device communication. * @urb: Urb structure used for device communication.
* @control: mac80211 control structure used to transmit data.
* @guardian_data: Set to 0, used for sending the guardian data. * @guardian_data: Set to 0, used for sending the guardian data.
* @guardian_urb: Urb structure used to send the guardian data. * @guardian_urb: Urb structure used to send the guardian data.
*/ */
struct queue_entry_priv_usb_bcn { struct queue_entry_priv_usb_bcn {
struct urb *urb; struct urb *urb;
struct ieee80211_tx_control control;
unsigned int guardian_data; unsigned int guardian_data;
struct urb *guardian_urb; struct urb *guardian_urb;
}; };

View File

@ -1018,49 +1018,34 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_rx->desc, 5, &word); rt2x00_desc_read(entry_priv->desc, 5, &word);
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
priv_rx->data_dma); entry_priv->data_dma);
rt2x00_desc_write(priv_rx->desc, 5, word); rt2x00_desc_write(entry_priv->desc, 5, word);
rt2x00_desc_read(priv_rx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
rt2x00_desc_write(priv_rx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry) struct queue_entry *entry)
{ {
struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word; u32 word;
rt2x00_desc_read(priv_tx->desc, 1, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
rt2x00_desc_write(priv_tx->desc, 1, word);
rt2x00_desc_read(priv_tx->desc, 5, &word);
rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
rt2x00_desc_write(priv_tx->desc, 5, word);
rt2x00_desc_read(priv_tx->desc, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
priv_tx->data_dma);
rt2x00_desc_write(priv_tx->desc, 6, word);
rt2x00_desc_read(priv_tx->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0); rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
rt2x00_desc_write(priv_tx->desc, 0, word); rt2x00_desc_write(entry_priv->desc, 0, word);
} }
static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
{ {
struct queue_entry_priv_pci_rx *priv_rx; struct queue_entry_priv_pci *entry_priv;
struct queue_entry_priv_pci_tx *priv_tx;
u32 reg; u32 reg;
/* /*
@ -1082,28 +1067,28 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00dev->tx[0].desc_size / 4); rt2x00dev->tx[0].desc_size / 4);
rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg); rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
priv_tx = rt2x00dev->tx[0].entries[0].priv_data; entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg); rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER, rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg); rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
priv_tx = rt2x00dev->tx[1].entries[0].priv_data; entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg); rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER, rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg); rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
priv_tx = rt2x00dev->tx[2].entries[0].priv_data; entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg); rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER, rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg); rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
priv_tx = rt2x00dev->tx[3].entries[0].priv_data; entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg); rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER, rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
priv_tx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg); rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg); rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
@ -1113,10 +1098,10 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4); rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg); rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
priv_rx = rt2x00dev->rx->entries[0].priv_data; entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg); rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER, rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
priv_rx->desc_dma); entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg); rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg); rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
@ -1526,10 +1511,10 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
*/ */
static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc)
struct ieee80211_tx_control *control)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
u32 word; u32 word;
@ -1543,6 +1528,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
rt2x00_desc_write(txd, 1, word); rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word); rt2x00_desc_read(txd, 2, &word);
@ -1553,11 +1539,19 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_desc_write(txd, 2, word); rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 5, &word); rt2x00_desc_read(txd, 5, &word);
rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
skbdesc->entry->entry_idx);
rt2x00_set_field32(&word, TXD_W5_TX_POWER, rt2x00_set_field32(&word, TXD_W5_TX_POWER,
TXPOWER_TO_DEV(rt2x00dev->tx_power)); TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word); rt2x00_desc_write(txd, 5, word);
rt2x00_desc_read(txd, 6, &word);
rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
entry_priv->data_dma);
rt2x00_desc_write(txd, 6, word);
if (skbdesc->desc_len > TXINFO_SIZE) { if (skbdesc->desc_len > TXINFO_SIZE) {
rt2x00_desc_read(txd, 11, &word); rt2x00_desc_read(txd, 11, &word);
rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
@ -1577,8 +1571,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags & test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST, rt2x00_set_field32(&word, TXD_W0_BURST,
@ -1667,14 +1660,13 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
static void rt61pci_fill_rxdone(struct queue_entry *entry, static void rt61pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc) struct rxdone_entry_desc *rxdesc)
{ {
struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data; struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0; u32 word0;
u32 word1; u32 word1;
rt2x00_desc_read(priv_rx->desc, 0, &word0); rt2x00_desc_read(entry_priv->desc, 0, &word0);
rt2x00_desc_read(priv_rx->desc, 1, &word1); rt2x00_desc_read(entry_priv->desc, 1, &word1);
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
@ -1688,7 +1680,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM)) if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@ -1703,7 +1694,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue; struct data_queue *queue;
struct queue_entry *entry; struct queue_entry *entry;
struct queue_entry *entry_done; struct queue_entry *entry_done;
struct queue_entry_priv_pci_tx *priv_tx; struct queue_entry_priv_pci *entry_priv;
struct txdone_entry_desc txdesc; struct txdone_entry_desc txdesc;
u32 word; u32 word;
u32 reg; u32 reg;
@ -1748,8 +1739,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
continue; continue;
entry = &queue->entries[index]; entry = &queue->entries[index];
priv_tx = entry->priv_data; entry_priv = entry->priv_data;
rt2x00_desc_read(priv_tx->desc, 0, &word); rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID)) !rt2x00_get_field32(word, TXD_W0_VALID))
@ -1764,7 +1755,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
"TX status report missed for entry %d\n", "TX status report missed for entry %d\n",
entry_done->entry_idx); entry_done->entry_idx);
txdesc.status = TX_FAIL_OTHER; txdesc.flags = 0;
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0; txdesc.retry = 0;
rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc); rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
@ -1774,7 +1766,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
/* /*
* Obtain the status about this packet. * Obtain the status about this packet.
*/ */
txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); txdesc.flags = 0;
switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) {
case 0: /* Success, maybe with retry */
__set_bit(TXDONE_SUCCESS, &txdesc.flags);
break;
case 6: /* Failure, excessive retries */
__set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
/* Don't break, this is a failed frame! */
default: /* Failure */
__set_bit(TXDONE_FAILURE, &txdesc.flags);
}
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc); rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@ -2248,7 +2250,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->extra_tx_headroom = 0;
rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -2356,21 +2357,30 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
return tsf; return tsf;
} }
static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct queue_entry_priv_pci_tx *priv_tx; struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
unsigned int beacon_base; unsigned int beacon_base;
u32 reg; u32 reg;
if (unlikely(!intf->beacon)) if (unlikely(!intf->beacon))
return -ENOBUFS; return -ENOBUFS;
priv_tx = intf->beacon->priv_data; /*
memset(priv_tx->desc, 0, intf->beacon->queue->desc_size); * Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
intf->beacon->skb = skb;
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
entry_priv = intf->beacon->priv_data;
memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
/* /*
* Fill in skb descriptor * Fill in skb descriptor
@ -2380,7 +2390,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED; skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data; skbdesc->data = skb->data;
skbdesc->data_len = skb->len; skbdesc->data_len = skb->len;
skbdesc->desc = priv_tx->desc; skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size; skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon; skbdesc->entry = intf->beacon;
@ -2398,7 +2408,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
rt2x00lib_write_tx_desc(rt2x00dev, skb, control); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
skbdesc->desc, skbdesc->desc_len); skbdesc->desc, skbdesc->desc_len);
@ -2457,21 +2467,21 @@ static const struct data_queue_desc rt61pci_queue_rx = {
.entry_num = RX_ENTRIES, .entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE, .desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_rx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt61pci_queue_tx = { static const struct data_queue_desc rt61pci_queue_tx = {
.entry_num = TX_ENTRIES, .entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct data_queue_desc rt61pci_queue_bcn = { static const struct data_queue_desc rt61pci_queue_bcn = {
.entry_num = 4 * BEACON_ENTRIES, .entry_num = 4 * BEACON_ENTRIES,
.data_size = 0, /* No DMA required for beacons */ .data_size = 0, /* No DMA required for beacons */
.desc_size = TXINFO_SIZE, .desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_pci_tx), .priv_size = sizeof(struct queue_entry_priv_pci),
}; };
static const struct rt2x00_ops rt61pci_ops = { static const struct rt2x00_ops rt61pci_ops = {
@ -2480,6 +2490,7 @@ static const struct rt2x00_ops rt61pci_ops = {
.max_ap_intf = 4, .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt61pci_queue_rx, .rx = &rt61pci_queue_rx,
.tx = &rt61pci_queue_tx, .tx = &rt61pci_queue_tx,
.bcn = &rt61pci_queue_bcn, .bcn = &rt61pci_queue_bcn,

View File

@ -53,6 +53,11 @@
#define BBP_SIZE 0x0080 #define BBP_SIZE 0x0080
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 4
/* /*
* PCI registers. * PCI registers.
*/ */

View File

@ -1255,8 +1255,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
*/ */
static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb, struct sk_buff *skb,
struct txentry_desc *txdesc, struct txentry_desc *txdesc)
struct ieee80211_tx_control *control)
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc; __le32 *txd = skbdesc->desc;
@ -1301,8 +1300,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags)); test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
!!(control->flags & test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
IEEE80211_TXCTL_LONG_RETRY_LIMIT));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST2, rt2x00_set_field32(&word, TXD_W0_BURST2,
@ -1405,25 +1403,26 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
{ {
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = (__le32 *)entry->skb->data; __le32 *rxd = (__le32 *)entry->skb->data;
unsigned int offset = entry->queue->desc_size + 2;
u32 word0; u32 word0;
u32 word1; u32 word1;
/* /*
* Copy descriptor to the available headroom inside the skbuffer. * Copy descriptor to the skb->cb array, this has 2 benefits:
* 1) Each descriptor word is 4 byte aligned.
* 2) Descriptor is safe from moving of frame data in rt2x00usb.
*/ */
skb_push(entry->skb, offset); skbdesc->desc_len =
memcpy(entry->skb->data, rxd, entry->queue->desc_size); min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
rxd = (__le32 *)entry->skb->data; memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
skbdesc->desc = entry->skb->cb;
rxd = (__le32 *)skbdesc->desc;
/* /*
* The descriptor is now aligned to 4 bytes and thus it is * It is now safe to read the descriptor on all architectures.
* now safe to read it on all architectures.
*/ */
rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1); rt2x00_desc_read(rxd, 1, &word1);
rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC; rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
@ -1437,25 +1436,18 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM)) if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS; rxdesc->dev_flags |= RXDONE_MY_BSS;
/* /*
* Adjust the skb memory window to the frame boundaries. * Set skb pointers, and update frame information.
*/ */
skb_pull(entry->skb, offset + entry->queue->desc_size); skb_pull(entry->skb, entry->queue->desc_size);
skb_trim(entry->skb, rxdesc->size); skb_trim(entry->skb, rxdesc->size);
/*
* Set descriptor and data pointer.
*/
skbdesc->data = entry->skb->data; skbdesc->data = entry->skb->data;
skbdesc->data_len = rxdesc->size; skbdesc->data_len = rxdesc->size;
skbdesc->desc = rxd;
skbdesc->desc_len = entry->queue->desc_size;
} }
/* /*
@ -1833,7 +1825,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM; IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@ -1957,18 +1948,27 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
#define rt73usb_get_tsf NULL #define rt73usb_get_tsf NULL
#endif #endif
static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rt2x00_dev *rt2x00dev = hw->priv; struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(control->vif); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct skb_frame_desc *skbdesc; struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
unsigned int beacon_base; unsigned int beacon_base;
u32 reg; u32 reg;
if (unlikely(!intf->beacon)) if (unlikely(!intf->beacon))
return -ENOBUFS; return -ENOBUFS;
/*
* Copy all TX descriptor information into txdesc,
* after that we are free to use the skb->cb array
* for our information.
*/
intf->beacon->skb = skb;
rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/* /*
* Add the descriptor in front of the skb. * Add the descriptor in front of the skb.
*/ */
@ -2001,7 +2001,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
* Write entire beacon with descriptor to register, * Write entire beacon with descriptor to register,
* and kick the beacon generator. * and kick the beacon generator.
*/ */
rt2x00lib_write_tx_desc(rt2x00dev, skb, control); rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE, rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, beacon_base, 0, USB_VENDOR_REQUEST_OUT, beacon_base, 0,
@ -2058,21 +2058,21 @@ static const struct data_queue_desc rt73usb_queue_rx = {
.entry_num = RX_ENTRIES, .entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE, .desc_size = RXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_rx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct data_queue_desc rt73usb_queue_tx = { static const struct data_queue_desc rt73usb_queue_tx = {
.entry_num = TX_ENTRIES, .entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE, .data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE, .desc_size = TXD_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct data_queue_desc rt73usb_queue_bcn = { static const struct data_queue_desc rt73usb_queue_bcn = {
.entry_num = 4 * BEACON_ENTRIES, .entry_num = 4 * BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE, .data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE, .desc_size = TXINFO_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb_tx), .priv_size = sizeof(struct queue_entry_priv_usb),
}; };
static const struct rt2x00_ops rt73usb_ops = { static const struct rt2x00_ops rt73usb_ops = {
@ -2081,6 +2081,7 @@ static const struct rt2x00_ops rt73usb_ops = {
.max_ap_intf = 4, .max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE, .eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE, .rf_size = RF_SIZE,
.tx_queues = NUM_TX_QUEUES,
.rx = &rt73usb_queue_rx, .rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx, .tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn, .bcn = &rt73usb_queue_bcn,

View File

@ -53,6 +53,11 @@
#define BBP_SIZE 0x0080 #define BBP_SIZE 0x0080
#define RF_SIZE 0x0014 #define RF_SIZE 0x0014
/*
* Number of TX queues.
*/
#define NUM_TX_QUEUES 4
/* /*
* USB registers. * USB registers.
*/ */

View File

@ -170,34 +170,29 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
while (skb_queue_len(&ring->queue)) { while (skb_queue_len(&ring->queue)) {
struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_status status; struct ieee80211_tx_info *info;
struct ieee80211_tx_control *control;
u32 flags = le32_to_cpu(entry->flags); u32 flags = le32_to_cpu(entry->flags);
if (flags & RTL8180_TX_DESC_FLAG_OWN) if (flags & RTL8180_TX_DESC_FLAG_OWN)
return; return;
memset(&status, 0, sizeof(status));
ring->idx = (ring->idx + 1) % ring->entries; ring->idx = (ring->idx + 1) % ring->entries;
skb = __skb_dequeue(&ring->queue); skb = __skb_dequeue(&ring->queue);
pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
skb->len, PCI_DMA_TODEVICE); skb->len, PCI_DMA_TODEVICE);
control = *((struct ieee80211_tx_control **)skb->cb); info = IEEE80211_SKB_CB(skb);
if (control) memset(&info->status, 0, sizeof(info->status));
memcpy(&status.control, control, sizeof(*control));
kfree(control);
if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (flags & RTL8180_TX_DESC_FLAG_TX_OK) if (flags & RTL8180_TX_DESC_FLAG_TX_OK)
status.flags = IEEE80211_TX_STATUS_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
else else
status.excessive_retries = 1; info->status.excessive_retries = 1;
} }
status.retry_count = flags & 0xFF; info->status.retry_count = flags & 0xFF;
ieee80211_tx_status_irqsafe(dev, skb, &status); ieee80211_tx_status_irqsafe(dev, skb);
if (ring->entries - skb_queue_len(&ring->queue) == 2) if (ring->entries - skb_queue_len(&ring->queue) == 2)
ieee80211_wake_queue(dev, prio); ieee80211_wake_queue(dev, prio);
} }
@ -238,9 +233,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl8180_priv *priv = dev->priv; struct rtl8180_priv *priv = dev->priv;
struct rtl8180_tx_ring *ring; struct rtl8180_tx_ring *ring;
struct rtl8180_tx_desc *entry; struct rtl8180_tx_desc *entry;
@ -251,46 +246,40 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
u16 plcp_len = 0; u16 plcp_len = 0;
__le16 rts_duration = 0; __le16 rts_duration = 0;
prio = control->queue; prio = skb_get_queue_mapping(skb);
ring = &priv->tx_ring[prio]; ring = &priv->tx_ring[prio];
mapping = pci_map_single(priv->pdev, skb->data, mapping = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE); skb->len, PCI_DMA_TODEVICE);
BUG_ON(!control->tx_rate);
tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
RTL8180_TX_DESC_FLAG_LS | RTL8180_TX_DESC_FLAG_LS |
(control->tx_rate->hw_value << 24) | skb->len; (ieee80211_get_tx_rate(dev, info)->hw_value << 24) |
skb->len;
if (priv->r8185) if (priv->r8185)
tx_flags |= RTL8180_TX_DESC_FLAG_DMA | tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
RTL8180_TX_DESC_FLAG_NO_ENC; RTL8180_TX_DESC_FLAG_NO_ENC;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
BUG_ON(!control->rts_cts_rate);
tx_flags |= RTL8180_TX_DESC_FLAG_RTS; tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
tx_flags |= control->rts_cts_rate->hw_value << 19; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
} else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
BUG_ON(!control->rts_cts_rate);
tx_flags |= RTL8180_TX_DESC_FLAG_CTS; tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
tx_flags |= control->rts_cts_rate->hw_value << 19; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
} }
*((struct ieee80211_tx_control **) skb->cb) = if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
kmemdup(control, sizeof(*control), GFP_ATOMIC);
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
control); info);
if (!priv->r8185) { if (!priv->r8185) {
unsigned int remainder; unsigned int remainder;
plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
(control->tx_rate->bitrate * 2) / 10); (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) % remainder = (16 * (skb->len + 4)) %
((control->tx_rate->bitrate * 2) / 10); ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
if (remainder > 0 && remainder <= 6) if (remainder > 0 && remainder <= 6)
plcp_len |= 1 << 15; plcp_len |= 1 << 15;
} }
@ -303,13 +292,13 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
entry->plcp_len = cpu_to_le16(plcp_len); entry->plcp_len = cpu_to_le16(plcp_len);
entry->tx_buf = cpu_to_le32(mapping); entry->tx_buf = cpu_to_le32(mapping);
entry->frame_len = cpu_to_le32(skb->len); entry->frame_len = cpu_to_le32(skb->len);
entry->flags2 = control->alt_retry_rate != NULL ? entry->flags2 = info->control.alt_retry_rate_idx >= 0 ?
control->alt_retry_rate->bitrate << 4 : 0; ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0;
entry->retry_limit = control->retry_limit; entry->retry_limit = info->control.retry_limit;
entry->flags = cpu_to_le32(tx_flags); entry->flags = cpu_to_le32(tx_flags);
__skb_queue_tail(&ring->queue, skb); __skb_queue_tail(&ring->queue, skb);
if (ring->entries - skb_queue_len(&ring->queue) < 2) if (ring->entries - skb_queue_len(&ring->queue) < 2)
ieee80211_stop_queue(dev, control->queue); ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@ -525,7 +514,6 @@ static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio)
pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
skb->len, PCI_DMA_TODEVICE); skb->len, PCI_DMA_TODEVICE);
kfree(*((struct ieee80211_tx_control **) skb->cb));
kfree_skb(skb); kfree_skb(skb);
ring->idx = (ring->idx + 1) % ring->entries; ring->idx = (ring->idx + 1) % ring->entries;
} }

View File

@ -44,12 +44,6 @@ struct rtl8187_rx_hdr {
__le64 mac_time; __le64 mac_time;
} __attribute__((packed)); } __attribute__((packed));
struct rtl8187_tx_info {
struct ieee80211_tx_control *control;
struct urb *urb;
struct ieee80211_hw *dev;
};
struct rtl8187_tx_hdr { struct rtl8187_tx_hdr {
__le32 flags; __le32 flags;
#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15) #define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15)

View File

@ -150,27 +150,22 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
static void rtl8187_tx_cb(struct urb *urb) static void rtl8187_tx_cb(struct urb *urb)
{ {
struct ieee80211_tx_status status;
struct sk_buff *skb = (struct sk_buff *)urb->context; struct sk_buff *skb = (struct sk_buff *)urb->context;
struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw = info->driver_data[0];
memset(&status, 0, sizeof(status)); usb_free_urb(info->driver_data[1]);
usb_free_urb(info->urb);
if (info->control)
memcpy(&status.control, info->control, sizeof(status.control));
kfree(info->control);
skb_pull(skb, sizeof(struct rtl8187_tx_hdr)); skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
status.flags |= IEEE80211_TX_STATUS_ACK; memset(&info->status, 0, sizeof(info->status));
ieee80211_tx_status_irqsafe(info->dev, skb, &status); info->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);
} }
static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct rtl8187_priv *priv = dev->priv; struct rtl8187_priv *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl8187_tx_hdr *hdr; struct rtl8187_tx_hdr *hdr;
struct rtl8187_tx_info *info;
struct urb *urb; struct urb *urb;
__le16 rts_dur = 0; __le16 rts_dur = 0;
u32 flags; u32 flags;
@ -185,33 +180,27 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
flags = skb->len; flags = skb->len;
flags |= RTL8187_TX_FLAG_NO_ENCRYPT; flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
BUG_ON(!control->tx_rate); flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
flags |= control->tx_rate->hw_value << 24;
if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data))
flags |= RTL8187_TX_FLAG_MORE_FRAG; flags |= RTL8187_TX_FLAG_MORE_FRAG;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
BUG_ON(!control->rts_cts_rate);
flags |= RTL8187_TX_FLAG_RTS; flags |= RTL8187_TX_FLAG_RTS;
flags |= control->rts_cts_rate->hw_value << 19; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
rts_dur = ieee80211_rts_duration(dev, priv->vif, rts_dur = ieee80211_rts_duration(dev, priv->vif,
skb->len, control); skb->len, info);
} else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
BUG_ON(!control->rts_cts_rate);
flags |= RTL8187_TX_FLAG_CTS; flags |= RTL8187_TX_FLAG_CTS;
flags |= control->rts_cts_rate->hw_value << 19; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
} }
hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags); hdr->flags = cpu_to_le32(flags);
hdr->len = 0; hdr->len = 0;
hdr->rts_duration = rts_dur; hdr->rts_duration = rts_dur;
hdr->retry = cpu_to_le32(control->retry_limit << 8); hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
info = (struct rtl8187_tx_info *)skb->cb; info->driver_data[0] = dev;
info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC); info->driver_data[1] = urb;
info->urb = urb;
info->dev = dev;
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2), usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
hdr, skb->len, rtl8187_tx_cb, skb); hdr, skb->len, rtl8187_tx_cb, skb);
rc = usb_submit_urb(urb, GFP_ATOMIC); rc = usb_submit_urb(urb, GFP_ATOMIC);

View File

@ -224,36 +224,6 @@ out:
return r; return r;
} }
/**
* clear_tx_skb_control_block - clears the control block of tx skbuffs
* @skb: a &struct sk_buff pointer
*
* This clears the control block of skbuff buffers, which were transmitted to
* the device. Notify that the function is not thread-safe, so prevent
* multiple calls.
*/
static void clear_tx_skb_control_block(struct sk_buff *skb)
{
struct zd_tx_skb_control_block *cb =
(struct zd_tx_skb_control_block *)skb->cb;
kfree(cb->control);
cb->control = NULL;
}
/**
* kfree_tx_skb - frees a tx skbuff
* @skb: a &struct sk_buff pointer
*
* Frees the tx skbuff. Frees also the allocated control structure in the
* control block if necessary.
*/
static void kfree_tx_skb(struct sk_buff *skb)
{
clear_tx_skb_control_block(skb);
dev_kfree_skb_any(skb);
}
static void zd_op_stop(struct ieee80211_hw *hw) static void zd_op_stop(struct ieee80211_hw *hw)
{ {
struct zd_mac *mac = zd_hw_mac(hw); struct zd_mac *mac = zd_hw_mac(hw);
@ -276,40 +246,15 @@ static void zd_op_stop(struct ieee80211_hw *hw)
while ((skb = skb_dequeue(ack_wait_queue))) while ((skb = skb_dequeue(ack_wait_queue)))
kfree_tx_skb(skb); dev_kfree_skb_any(skb);
}
/**
* init_tx_skb_control_block - initializes skb control block
* @skb: a &sk_buff pointer
* @dev: pointer to the mac80221 device
* @control: mac80211 tx control applying for the frame in @skb
*
* Initializes the control block of the skbuff to be transmitted.
*/
static int init_tx_skb_control_block(struct sk_buff *skb,
struct ieee80211_hw *hw,
struct ieee80211_tx_control *control)
{
struct zd_tx_skb_control_block *cb =
(struct zd_tx_skb_control_block *)skb->cb;
ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb));
memset(cb, 0, sizeof(*cb));
cb->hw= hw;
cb->control = kmalloc(sizeof(*control), GFP_ATOMIC);
if (cb->control == NULL)
return -ENOMEM;
memcpy(cb->control, control, sizeof(*control));
return 0;
} }
/** /**
* tx_status - reports tx status of a packet if required * tx_status - reports tx status of a packet if required
* @hw - a &struct ieee80211_hw pointer * @hw - a &struct ieee80211_hw pointer
* @skb - a sk-buffer * @skb - a sk-buffer
* @status - the tx status of the packet without control information * @flags: extra flags to set in the TX status info
* @ackssi: ACK signal strength
* @success - True for successfull transmission of the frame * @success - True for successfull transmission of the frame
* *
* This information calls ieee80211_tx_status_irqsafe() if required by the * This information calls ieee80211_tx_status_irqsafe() if required by the
@ -319,18 +264,17 @@ static int init_tx_skb_control_block(struct sk_buff *skb,
* If no status information has been requested, the skb is freed. * If no status information has been requested, the skb is freed.
*/ */
static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_tx_status *status, u32 flags, int ackssi, bool success)
bool success)
{ {
struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
skb->cb;
memset(&info->status, 0, sizeof(info->status));
ZD_ASSERT(cb->control != NULL);
memcpy(&status->control, cb->control, sizeof(status->control));
if (!success) if (!success)
status->excessive_retries = 1; info->status.excessive_retries = 1;
clear_tx_skb_control_block(skb); info->flags |= flags;
ieee80211_tx_status_irqsafe(hw, skb, status); info->status.ack_signal = ackssi;
ieee80211_tx_status_irqsafe(hw, skb);
} }
/** /**
@ -345,15 +289,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
{ {
struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_tx_status status;
skb = skb_dequeue(q); skb = skb_dequeue(q);
if (skb == NULL) if (skb == NULL)
return; return;
memset(&status, 0, sizeof(status)); tx_status(hw, skb, 0, 0, 0);
tx_status(hw, skb, &status, 0);
} }
/** /**
@ -368,28 +309,20 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
*/ */
void zd_mac_tx_to_dev(struct sk_buff *skb, int error) void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
{ {
struct zd_tx_skb_control_block *cb = struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
(struct zd_tx_skb_control_block *)skb->cb; struct ieee80211_hw *hw = info->driver_data[0];
struct ieee80211_hw *hw = cb->hw;
if (likely(cb->control)) { skb_pull(skb, sizeof(struct zd_ctrlset));
skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error ||
if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
(cb->control->flags & IEEE80211_TXCTL_NO_ACK))) tx_status(hw, skb, 0, 0, !error);
{
struct ieee80211_tx_status status;
memset(&status, 0, sizeof(status));
tx_status(hw, skb, &status, !error);
} else {
struct sk_buff_head *q =
&zd_hw_mac(hw)->ack_wait_queue;
skb_queue_tail(q, skb);
while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
zd_mac_tx_failed(hw);
}
} else { } else {
kfree_tx_skb(skb); struct sk_buff_head *q =
&zd_hw_mac(hw)->ack_wait_queue;
skb_queue_tail(q, skb);
while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
zd_mac_tx_failed(hw);
} }
} }
@ -454,7 +387,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control = 0; cs->control = 0;
/* First fragment */ /* First fragment */
if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT) if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
/* Multicast */ /* Multicast */
@ -466,10 +399,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
(IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL)) (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
cs->control |= ZD_CS_PS_POLL_FRAME; cs->control |= ZD_CS_PS_POLL_FRAME;
if (flags & IEEE80211_TXCTL_USE_RTS_CTS) if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
cs->control |= ZD_CS_RTS; cs->control |= ZD_CS_RTS;
if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT) if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
cs->control |= ZD_CS_SELF_CTS; cs->control |= ZD_CS_SELF_CTS;
/* FIXME: Management frame? */ /* FIXME: Management frame? */
@ -516,25 +449,28 @@ void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
} }
static int fill_ctrlset(struct zd_mac *mac, static int fill_ctrlset(struct zd_mac *mac,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
int r; int r;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned int frag_len = skb->len + FCS_LEN; unsigned int frag_len = skb->len + FCS_LEN;
unsigned int packet_length; unsigned int packet_length;
struct ieee80211_rate *txrate;
struct zd_ctrlset *cs = (struct zd_ctrlset *) struct zd_ctrlset *cs = (struct zd_ctrlset *)
skb_push(skb, sizeof(struct zd_ctrlset)); skb_push(skb, sizeof(struct zd_ctrlset));
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
ZD_ASSERT(frag_len <= 0xffff); ZD_ASSERT(frag_len <= 0xffff);
cs->modulation = control->tx_rate->hw_value; txrate = ieee80211_get_tx_rate(mac->hw, info);
if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
cs->modulation = control->tx_rate->hw_value_short; cs->modulation = txrate->hw_value;
if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
cs->modulation = txrate->hw_value_short;
cs->tx_length = cpu_to_le16(frag_len); cs->tx_length = cpu_to_le16(frag_len);
cs_set_control(mac, cs, hdr, control->flags); cs_set_control(mac, cs, hdr, info->flags);
packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
ZD_ASSERT(packet_length <= 0xffff); ZD_ASSERT(packet_length <= 0xffff);
@ -579,24 +515,21 @@ static int fill_ctrlset(struct zd_mac *mac,
* control block of the skbuff will be initialized. If necessary the incoming * control block of the skbuff will be initialized. If necessary the incoming
* mac80211 queues will be stopped. * mac80211 queues will be stopped.
*/ */
static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_control *control)
{ {
struct zd_mac *mac = zd_hw_mac(hw); struct zd_mac *mac = zd_hw_mac(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int r; int r;
r = fill_ctrlset(mac, skb, control); r = fill_ctrlset(mac, skb);
if (r) if (r)
return r; return r;
r = init_tx_skb_control_block(skb, hw, control); info->driver_data[0] = hw;
r = zd_usb_tx(&mac->chip.usb, skb);
if (r) if (r)
return r; return r;
r = zd_usb_tx(&mac->chip.usb, skb);
if (r) {
clear_tx_skb_control_block(skb);
return r;
}
return 0; return 0;
} }
@ -634,13 +567,8 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
tx_hdr = (struct ieee80211_hdr *)skb->data; tx_hdr = (struct ieee80211_hdr *)skb->data;
if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
{ {
struct ieee80211_tx_status status;
memset(&status, 0, sizeof(status));
status.flags = IEEE80211_TX_STATUS_ACK;
status.ack_signal = stats->signal;
__skb_unlink(skb, q); __skb_unlink(skb, q);
tx_status(hw, skb, &status, 1); tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
goto out; goto out;
} }
} }
@ -944,8 +872,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
} }
static int zd_op_beacon_update(struct ieee80211_hw *hw, static int zd_op_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *skb, struct sk_buff *skb)
struct ieee80211_tx_control *ctl)
{ {
struct zd_mac *mac = zd_hw_mac(hw); struct zd_mac *mac = zd_hw_mac(hw);
zd_mac_config_beacon(hw, skb); zd_mac_config_beacon(hw, skb);

View File

@ -149,22 +149,6 @@ struct housekeeping {
struct delayed_work link_led_work; struct delayed_work link_led_work;
}; };
/**
* struct zd_tx_skb_control_block - control block for tx skbuffs
* @control: &struct ieee80211_tx_control pointer
* @context: context pointer
*
* This structure is used to fill the cb field in an &sk_buff to transmit.
* The control field is NULL, if there is no requirement from the mac80211
* stack to report about the packet ACK. This is the case if the flag
* IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control.
*/
struct zd_tx_skb_control_block {
struct ieee80211_tx_control *control;
struct ieee80211_hw *hw;
void *context;
};
#define ZD_MAC_STATS_BUFFER_SIZE 16 #define ZD_MAC_STATS_BUFFER_SIZE 16
#define ZD_MAC_MAX_ACK_WAITERS 10 #define ZD_MAC_MAX_ACK_WAITERS 10

View File

@ -169,10 +169,11 @@ static int upload_code(struct usb_device *udev,
if (flags & REBOOT) { if (flags & REBOOT) {
u8 ret; u8 ret;
/* Use "DMA-aware" buffer. */
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_FIRMWARE_CONFIRM, USB_REQ_FIRMWARE_CONFIRM,
USB_DIR_IN | USB_TYPE_VENDOR, USB_DIR_IN | USB_TYPE_VENDOR,
0, 0, &ret, sizeof(ret), 5000 /* ms */); 0, 0, p, sizeof(ret), 5000 /* ms */);
if (r != sizeof(ret)) { if (r != sizeof(ret)) {
dev_err(&udev->dev, dev_err(&udev->dev,
"control request firmeware confirmation failed." "control request firmeware confirmation failed."
@ -181,6 +182,7 @@ static int upload_code(struct usb_device *udev,
r = -ENODEV; r = -ENODEV;
goto error; goto error;
} }
ret = p[0];
if (ret & 0x80) { if (ret & 0x80) {
dev_err(&udev->dev, dev_err(&udev->dev,
"Internal error while downloading." "Internal error while downloading."
@ -312,22 +314,31 @@ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
{ {
int r; int r;
struct usb_device *udev = zd_usb_to_usbdev(usb); struct usb_device *udev = zd_usb_to_usbdev(usb);
u8 *buf;
/* Use "DMA-aware" buffer. */
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
data, len, 5000); buf, len, 5000);
if (r < 0) { if (r < 0) {
dev_err(&udev->dev, dev_err(&udev->dev,
"read over firmware interface failed: %d\n", r); "read over firmware interface failed: %d\n", r);
return r; goto exit;
} else if (r != len) { } else if (r != len) {
dev_err(&udev->dev, dev_err(&udev->dev,
"incomplete read over firmware interface: %d/%d\n", "incomplete read over firmware interface: %d/%d\n",
r, len); r, len);
return -EIO; r = -EIO;
goto exit;
} }
r = 0;
return 0; memcpy(data, buf, len);
exit:
kfree(buf);
return r;
} }
#define urb_dev(urb) (&(urb)->dev->dev) #define urb_dev(urb) (&(urb)->dev->dev)
@ -869,7 +880,7 @@ static void tx_urb_complete(struct urb *urb)
{ {
int r; int r;
struct sk_buff *skb; struct sk_buff *skb;
struct zd_tx_skb_control_block *cb; struct ieee80211_tx_info *info;
struct zd_usb *usb; struct zd_usb *usb;
switch (urb->status) { switch (urb->status) {
@ -893,8 +904,8 @@ free_urb:
* grab 'usb' pointer before handing off the skb (since * grab 'usb' pointer before handing off the skb (since
* it might be freed by zd_mac_tx_to_dev or mac80211) * it might be freed by zd_mac_tx_to_dev or mac80211)
*/ */
cb = (struct zd_tx_skb_control_block *)skb->cb; info = IEEE80211_SKB_CB(skb);
usb = &zd_hw_mac(cb->hw)->chip.usb; usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
zd_mac_tx_to_dev(skb, urb->status); zd_mac_tx_to_dev(skb, urb->status);
free_tx_urb(usb, urb); free_tx_urb(usb, urb);
tx_dec_submitted_urbs(usb); tx_dec_submitted_urbs(usb);

View File

@ -306,20 +306,32 @@ struct ieee80211_ht_addt_info {
#define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_SGI_40 0x0040
#define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_DELAY_BA 0x0400
#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
/* 802.11n HT capability AMPDU settings */
#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 #define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03
#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C #define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C
/* 802.11n HT capability MSC set */
#define IEEE80211_SUPP_MCS_SET_UEQM 4
#define IEEE80211_HT_CAP_MAX_STREAMS 4
#define IEEE80211_SUPP_MCS_SET_LEN 10
/* maximum streams the spec allows */
#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01
#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02
#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C
#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10
/* 802.11n HT IE masks */ /* 802.11n HT IE masks */
#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 #define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03
#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01
#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03
#define IEEE80211_HT_IE_CHA_WIDTH 0x04 #define IEEE80211_HT_IE_CHA_WIDTH 0x04
#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 #define IEEE80211_HT_IE_HT_PROTECTION 0x0003
#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004
#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010
/* MIMO Power Save Modes */ /* MIMO Power Save Modes */
#define WLAN_HT_CAP_MIMO_PS_STATIC 0 #define WLAN_HT_CAP_MIMO_PS_STATIC 0
#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 #define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1
#define WLAN_HT_CAP_MIMO_PS_INVALID 2 #define WLAN_HT_CAP_MIMO_PS_INVALID 2
#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 #define WLAN_HT_CAP_MIMO_PS_DISABLED 3
/* Authentication algorithms */ /* Authentication algorithms */
#define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_OPEN 0

Some files were not shown because too many files have changed in this diff Show More