diff options
| author | John W. Linville <linville@tuxdriver.com> | 2010-12-16 15:21:33 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-12-16 15:21:33 -0500 |
| commit | 5928b91acae97622a6f2e679eb7a9f19bed68e3e (patch) | |
| tree | 02d55145d355735b12398ad3eab61a72c78d5c4e | |
| parent | 7d5f01ad536afebde9a1c81d985f8d0eaf2a9ab6 (diff) | |
| parent | 248daa084cee4b212ff4408e9c9b05b3bdc0da0d (diff) | |
Merge branch 'wl12xx-next' of git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx
| -rw-r--r-- | drivers/net/wireless/wl12xx/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/Makefile | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/acx.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/acx.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/boot.c | 17 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/boot.h | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/cmd.c | 69 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/cmd.h | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/debugfs.c | 192 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/init.c | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/io.c | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 119 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/scan.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/sdio_test.c | 520 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 60 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx.h | 129 | ||||
| -rw-r--r-- | drivers/net/wireless/wl12xx/wl12xx_80211.h | 17 |
17 files changed, 848 insertions, 324 deletions
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index d2adeb1f72b7..0e65bce457d6 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig | |||
| @@ -52,6 +52,16 @@ config WL12XX_SDIO | |||
| 52 | If you choose to build a module, it'll be called wl12xx_sdio. | 52 | If you choose to build a module, it'll be called wl12xx_sdio. |
| 53 | Say N if unsure. | 53 | Say N if unsure. |
| 54 | 54 | ||
| 55 | config WL12XX_SDIO_TEST | ||
| 56 | tristate "TI wl12xx SDIO testing support" | ||
| 57 | depends on WL12XX && MMC | ||
| 58 | default n | ||
| 59 | ---help--- | ||
| 60 | This module adds support for the SDIO bus testing with the | ||
| 61 | TI wl12xx chipsets. You probably don't want this unless you are | ||
| 62 | testing a new hardware platform. Select this if you want to test the | ||
| 63 | SDIO bus which is connected to the wl12xx chip. | ||
| 64 | |||
| 55 | config WL12XX_PLATFORM_DATA | 65 | config WL12XX_PLATFORM_DATA |
| 56 | bool | 66 | bool |
| 57 | depends on WL12XX_SDIO != n || WL1251_SDIO != n | 67 | depends on WL12XX_SDIO != n || WL1251_SDIO != n |
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 005a758174d9..521c0414e52e 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile | |||
| @@ -3,11 +3,14 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ | |||
| 3 | 3 | ||
| 4 | wl12xx_spi-objs = spi.o | 4 | wl12xx_spi-objs = spi.o |
| 5 | wl12xx_sdio-objs = sdio.o | 5 | wl12xx_sdio-objs = sdio.o |
| 6 | wl12xx_sdio_test-objs = sdio_test.o | ||
| 6 | 7 | ||
| 7 | wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o | 8 | wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o |
| 8 | obj-$(CONFIG_WL12XX) += wl12xx.o | 9 | obj-$(CONFIG_WL12XX) += wl12xx.o |
| 9 | obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o | 10 | obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o |
| 10 | obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o | 11 | obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o |
| 11 | 12 | ||
| 13 | obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o | ||
| 14 | |||
| 12 | # small builtin driver bit | 15 | # small builtin driver bit |
| 13 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o | 16 | obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o |
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 7cbaeb6d2a37..cc4068d2b4a8 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c | |||
| @@ -1041,7 +1041,7 @@ out: | |||
| 1041 | return ret; | 1041 | return ret; |
| 1042 | } | 1042 | } |
| 1043 | 1043 | ||
| 1044 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address) | 1044 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) |
| 1045 | { | 1045 | { |
| 1046 | struct wl1271_acx_arp_filter *acx; | 1046 | struct wl1271_acx_arp_filter *acx; |
| 1047 | int ret; | 1047 | int ret; |
| @@ -1057,7 +1057,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address) | |||
| 1057 | acx->version = ACX_IPV4_VERSION; | 1057 | acx->version = ACX_IPV4_VERSION; |
| 1058 | acx->enable = enable; | 1058 | acx->enable = enable; |
| 1059 | 1059 | ||
| 1060 | if (enable == true) | 1060 | if (enable) |
| 1061 | memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); | 1061 | memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); |
| 1062 | 1062 | ||
| 1063 | ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, | 1063 | ret = wl1271_cmd_configure(wl, ACX_ARP_IP_FILTER, |
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 75a6306ff554..9cbc3f40c8dd 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h | |||
| @@ -868,10 +868,15 @@ struct wl1271_acx_bet_enable { | |||
| 868 | #define ACX_IPV4_VERSION 4 | 868 | #define ACX_IPV4_VERSION 4 |
| 869 | #define ACX_IPV6_VERSION 6 | 869 | #define ACX_IPV6_VERSION 6 |
| 870 | #define ACX_IPV4_ADDR_SIZE 4 | 870 | #define ACX_IPV4_ADDR_SIZE 4 |
| 871 | |||
| 872 | /* bitmap of enabled arp_filter features */ | ||
| 873 | #define ACX_ARP_FILTER_ARP_FILTERING BIT(0) | ||
| 874 | #define ACX_ARP_FILTER_AUTO_ARP BIT(1) | ||
| 875 | |||
| 871 | struct wl1271_acx_arp_filter { | 876 | struct wl1271_acx_arp_filter { |
| 872 | struct acx_header header; | 877 | struct acx_header header; |
| 873 | u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ | 878 | u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ |
| 874 | u8 enable; /* 1 to enable ARP filtering, 0 to disable */ | 879 | u8 enable; /* bitmap of enabled ARP filtering features */ |
| 875 | u8 padding[2]; | 880 | u8 padding[2]; |
| 876 | u8 address[16]; /* The configured device IP address - all ARP | 881 | u8 address[16]; /* The configured device IP address - all ARP |
| 877 | requests directed to this IP address will pass | 882 | requests directed to this IP address will pass |
| @@ -1168,7 +1173,7 @@ int wl1271_acx_init_mem_config(struct wl1271 *wl); | |||
| 1168 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); | 1173 | int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); |
| 1169 | int wl1271_acx_smart_reflex(struct wl1271 *wl); | 1174 | int wl1271_acx_smart_reflex(struct wl1271 *wl); |
| 1170 | int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); | 1175 | int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); |
| 1171 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, __be32 address); | 1176 | int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address); |
| 1172 | int wl1271_acx_pm_config(struct wl1271 *wl); | 1177 | int wl1271_acx_pm_config(struct wl1271 *wl); |
| 1173 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); | 1178 | int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable); |
| 1174 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); | 1179 | int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); |
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 1eafb8175832..4a9f929725fd 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c | |||
| @@ -467,7 +467,8 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) | |||
| 467 | wl->hw_pg_ver = (s8)fuse; | 467 | wl->hw_pg_ver = (s8)fuse; |
| 468 | } | 468 | } |
| 469 | 469 | ||
| 470 | int wl1271_boot(struct wl1271 *wl) | 470 | /* uploads NVS and firmware */ |
| 471 | int wl1271_load_firmware(struct wl1271 *wl) | ||
| 471 | { | 472 | { |
| 472 | int ret = 0; | 473 | int ret = 0; |
| 473 | u32 tmp, clk, pause; | 474 | u32 tmp, clk, pause; |
| @@ -572,6 +573,20 @@ int wl1271_boot(struct wl1271 *wl) | |||
| 572 | if (ret < 0) | 573 | if (ret < 0) |
| 573 | goto out; | 574 | goto out; |
| 574 | 575 | ||
| 576 | out: | ||
| 577 | return ret; | ||
| 578 | } | ||
| 579 | EXPORT_SYMBOL_GPL(wl1271_load_firmware); | ||
| 580 | |||
| 581 | int wl1271_boot(struct wl1271 *wl) | ||
| 582 | { | ||
| 583 | int ret; | ||
| 584 | |||
| 585 | /* upload NVS and firmware */ | ||
| 586 | ret = wl1271_load_firmware(wl); | ||
| 587 | if (ret) | ||
| 588 | return ret; | ||
| 589 | |||
| 575 | /* 10.5 start firmware */ | 590 | /* 10.5 start firmware */ |
| 576 | ret = wl1271_boot_run_firmware(wl); | 591 | ret = wl1271_boot_run_firmware(wl); |
| 577 | if (ret < 0) | 592 | if (ret < 0) |
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index c7d771959f3a..d67dcffa31eb 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include "wl12xx.h" | 27 | #include "wl12xx.h" |
| 28 | 28 | ||
| 29 | int wl1271_boot(struct wl1271 *wl); | 29 | int wl1271_boot(struct wl1271 *wl); |
| 30 | int wl1271_load_firmware(struct wl1271 *wl); | ||
| 30 | 31 | ||
| 31 | #define WL1271_NO_SUBBANDS 8 | 32 | #define WL1271_NO_SUBBANDS 8 |
| 32 | #define WL1271_NO_POWER_LEVELS 4 | 33 | #define WL1271_NO_POWER_LEVELS 4 |
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index f3d0541aaad6..0106628aa5a2 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c | |||
| @@ -611,6 +611,75 @@ out: | |||
| 611 | return ret; | 611 | return ret; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | ||
| 615 | struct sk_buff *skb) | ||
| 616 | { | ||
| 617 | int ret; | ||
| 618 | |||
| 619 | if (!skb) | ||
| 620 | skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); | ||
| 621 | if (!skb) | ||
| 622 | goto out; | ||
| 623 | |||
| 624 | wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); | ||
| 625 | |||
| 626 | if (wl->band == IEEE80211_BAND_2GHZ) | ||
| 627 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||
| 628 | skb->data, skb->len, 0, | ||
| 629 | wl->conf.tx.basic_rate); | ||
| 630 | else | ||
| 631 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | ||
| 632 | skb->data, skb->len, 0, | ||
| 633 | wl->conf.tx.basic_rate_5); | ||
| 634 | |||
| 635 | if (ret < 0) | ||
| 636 | wl1271_error("Unable to set ap probe request template."); | ||
| 637 | |||
| 638 | out: | ||
| 639 | return skb; | ||
| 640 | } | ||
| 641 | |||
| 642 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr) | ||
| 643 | { | ||
| 644 | int ret; | ||
| 645 | struct wl12xx_arp_rsp_template tmpl; | ||
| 646 | struct ieee80211_hdr_3addr *hdr; | ||
| 647 | struct arphdr *arp_hdr; | ||
| 648 | |||
| 649 | memset(&tmpl, 0, sizeof(tmpl)); | ||
| 650 | |||
| 651 | /* mac80211 header */ | ||
| 652 | hdr = &tmpl.hdr; | ||
| 653 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
| 654 | IEEE80211_STYPE_DATA | | ||
| 655 | IEEE80211_FCTL_TODS); | ||
| 656 | memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN); | ||
| 657 | memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN); | ||
| 658 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
| 659 | |||
| 660 | /* llc layer */ | ||
| 661 | memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header)); | ||
| 662 | tmpl.llc_type = htons(ETH_P_ARP); | ||
| 663 | |||
| 664 | /* arp header */ | ||
| 665 | arp_hdr = &tmpl.arp_hdr; | ||
| 666 | arp_hdr->ar_hrd = htons(ARPHRD_ETHER); | ||
| 667 | arp_hdr->ar_pro = htons(ETH_P_IP); | ||
| 668 | arp_hdr->ar_hln = ETH_ALEN; | ||
| 669 | arp_hdr->ar_pln = 4; | ||
| 670 | arp_hdr->ar_op = htons(ARPOP_REPLY); | ||
| 671 | |||
| 672 | /* arp payload */ | ||
| 673 | memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN); | ||
| 674 | tmpl.sender_ip = ip_addr; | ||
| 675 | |||
| 676 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, | ||
| 677 | &tmpl, sizeof(tmpl), 0, | ||
| 678 | wl->basic_rate); | ||
| 679 | |||
| 680 | return ret; | ||
| 681 | } | ||
| 682 | |||
| 614 | int wl1271_build_qos_null_data(struct wl1271 *wl) | 683 | int wl1271_build_qos_null_data(struct wl1271 *wl) |
| 615 | { | 684 | { |
| 616 | struct ieee80211_qos_hdr template; | 685 | struct ieee80211_qos_hdr template; |
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 16d1bf814e76..2a1d9db7ceb8 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h | |||
| @@ -49,6 +49,9 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); | |||
| 49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, | 49 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, |
| 50 | const u8 *ssid, size_t ssid_len, | 50 | const u8 *ssid, size_t ssid_len, |
| 51 | const u8 *ie, size_t ie_len, u8 band); | 51 | const u8 *ie, size_t ie_len, u8 band); |
| 52 | struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, | ||
| 53 | struct sk_buff *skb); | ||
| 54 | int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); | ||
| 52 | int wl1271_build_qos_null_data(struct wl1271 *wl); | 55 | int wl1271_build_qos_null_data(struct wl1271 *wl); |
| 53 | int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); | 56 | int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); |
| 54 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); | 57 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); |
| @@ -122,6 +125,7 @@ enum cmd_templ { | |||
| 122 | CMD_TEMPL_CTS, /* | 125 | CMD_TEMPL_CTS, /* |
| 123 | * For CTS-to-self (FastCTS) mechanism | 126 | * For CTS-to-self (FastCTS) mechanism |
| 124 | * for BT/WLAN coexistence (SoftGemini). */ | 127 | * for BT/WLAN coexistence (SoftGemini). */ |
| 128 | CMD_TEMPL_ARP_RSP, | ||
| 125 | CMD_TEMPL_MAX = 0xff | 129 | CMD_TEMPL_MAX = 0xff |
| 126 | }; | 130 | }; |
| 127 | 131 | ||
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index dd71b7d2105c..ec6077760157 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c | |||
| @@ -66,19 +66,10 @@ static const struct file_operations name## _ops = { \ | |||
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | #define DEBUGFS_ADD(name, parent) \ | 68 | #define DEBUGFS_ADD(name, parent) \ |
| 69 | wl->debugfs.name = debugfs_create_file(#name, 0400, parent, \ | 69 | entry = debugfs_create_file(#name, 0400, parent, \ |
| 70 | wl, &name## _ops); \ | 70 | wl, &name## _ops); \ |
| 71 | if (IS_ERR(wl->debugfs.name)) { \ | 71 | if (!entry || IS_ERR(entry)) \ |
| 72 | ret = PTR_ERR(wl->debugfs.name); \ | 72 | goto err; \ |
| 73 | wl->debugfs.name = NULL; \ | ||
| 74 | goto out; \ | ||
| 75 | } | ||
| 76 | |||
| 77 | #define DEBUGFS_DEL(name) \ | ||
| 78 | do { \ | ||
| 79 | debugfs_remove(wl->debugfs.name); \ | ||
| 80 | wl->debugfs.name = NULL; \ | ||
| 81 | } while (0) | ||
| 82 | 73 | ||
| 83 | #define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ | 74 | #define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ |
| 84 | static ssize_t sub## _ ##name## _read(struct file *file, \ | 75 | static ssize_t sub## _ ##name## _read(struct file *file, \ |
| @@ -100,10 +91,7 @@ static const struct file_operations sub## _ ##name## _ops = { \ | |||
| 100 | }; | 91 | }; |
| 101 | 92 | ||
| 102 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ | 93 | #define DEBUGFS_FWSTATS_ADD(sub, name) \ |
| 103 | DEBUGFS_ADD(sub## _ ##name, wl->debugfs.fw_statistics) | 94 | DEBUGFS_ADD(sub## _ ##name, stats) |
| 104 | |||
| 105 | #define DEBUGFS_FWSTATS_DEL(sub, name) \ | ||
| 106 | DEBUGFS_DEL(sub## _ ##name) | ||
| 107 | 95 | ||
| 108 | static void wl1271_debugfs_update_stats(struct wl1271 *wl) | 96 | static void wl1271_debugfs_update_stats(struct wl1271 *wl) |
| 109 | { | 97 | { |
| @@ -237,7 +225,7 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, | |||
| 237 | char buf[20]; | 225 | char buf[20]; |
| 238 | int res; | 226 | int res; |
| 239 | 227 | ||
| 240 | queue_len = skb_queue_len(&wl->tx_queue); | 228 | queue_len = wl->tx_queue_count; |
| 241 | 229 | ||
| 242 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); | 230 | res = scnprintf(buf, sizeof(buf), "%u\n", queue_len); |
| 243 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 231 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
| @@ -305,109 +293,16 @@ static const struct file_operations gpio_power_ops = { | |||
| 305 | .llseek = default_llseek, | 293 | .llseek = default_llseek, |
| 306 | }; | 294 | }; |
| 307 | 295 | ||
| 308 | static void wl1271_debugfs_delete_files(struct wl1271 *wl) | ||
| 309 | { | ||
| 310 | DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||
| 311 | |||
| 312 | DEBUGFS_FWSTATS_DEL(rx, out_of_mem); | ||
| 313 | DEBUGFS_FWSTATS_DEL(rx, hdr_overflow); | ||
| 314 | DEBUGFS_FWSTATS_DEL(rx, hw_stuck); | ||
| 315 | DEBUGFS_FWSTATS_DEL(rx, dropped); | ||
| 316 | DEBUGFS_FWSTATS_DEL(rx, fcs_err); | ||
| 317 | DEBUGFS_FWSTATS_DEL(rx, xfr_hint_trig); | ||
| 318 | DEBUGFS_FWSTATS_DEL(rx, path_reset); | ||
| 319 | DEBUGFS_FWSTATS_DEL(rx, reset_counter); | ||
| 320 | |||
| 321 | DEBUGFS_FWSTATS_DEL(dma, rx_requested); | ||
| 322 | DEBUGFS_FWSTATS_DEL(dma, rx_errors); | ||
| 323 | DEBUGFS_FWSTATS_DEL(dma, tx_requested); | ||
| 324 | DEBUGFS_FWSTATS_DEL(dma, tx_errors); | ||
| 325 | |||
| 326 | DEBUGFS_FWSTATS_DEL(isr, cmd_cmplt); | ||
| 327 | DEBUGFS_FWSTATS_DEL(isr, fiqs); | ||
| 328 | DEBUGFS_FWSTATS_DEL(isr, rx_headers); | ||
| 329 | DEBUGFS_FWSTATS_DEL(isr, rx_mem_overflow); | ||
| 330 | DEBUGFS_FWSTATS_DEL(isr, rx_rdys); | ||
| 331 | DEBUGFS_FWSTATS_DEL(isr, irqs); | ||
| 332 | DEBUGFS_FWSTATS_DEL(isr, tx_procs); | ||
| 333 | DEBUGFS_FWSTATS_DEL(isr, decrypt_done); | ||
| 334 | DEBUGFS_FWSTATS_DEL(isr, dma0_done); | ||
| 335 | DEBUGFS_FWSTATS_DEL(isr, dma1_done); | ||
| 336 | DEBUGFS_FWSTATS_DEL(isr, tx_exch_complete); | ||
| 337 | DEBUGFS_FWSTATS_DEL(isr, commands); | ||
| 338 | DEBUGFS_FWSTATS_DEL(isr, rx_procs); | ||
| 339 | DEBUGFS_FWSTATS_DEL(isr, hw_pm_mode_changes); | ||
| 340 | DEBUGFS_FWSTATS_DEL(isr, host_acknowledges); | ||
| 341 | DEBUGFS_FWSTATS_DEL(isr, pci_pm); | ||
| 342 | DEBUGFS_FWSTATS_DEL(isr, wakeups); | ||
| 343 | DEBUGFS_FWSTATS_DEL(isr, low_rssi); | ||
| 344 | |||
| 345 | DEBUGFS_FWSTATS_DEL(wep, addr_key_count); | ||
| 346 | DEBUGFS_FWSTATS_DEL(wep, default_key_count); | ||
| 347 | /* skipping wep.reserved */ | ||
| 348 | DEBUGFS_FWSTATS_DEL(wep, key_not_found); | ||
| 349 | DEBUGFS_FWSTATS_DEL(wep, decrypt_fail); | ||
| 350 | DEBUGFS_FWSTATS_DEL(wep, packets); | ||
| 351 | DEBUGFS_FWSTATS_DEL(wep, interrupt); | ||
| 352 | |||
| 353 | DEBUGFS_FWSTATS_DEL(pwr, ps_enter); | ||
| 354 | DEBUGFS_FWSTATS_DEL(pwr, elp_enter); | ||
| 355 | DEBUGFS_FWSTATS_DEL(pwr, missing_bcns); | ||
| 356 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_host); | ||
| 357 | DEBUGFS_FWSTATS_DEL(pwr, wake_on_timer_exp); | ||
| 358 | DEBUGFS_FWSTATS_DEL(pwr, tx_with_ps); | ||
| 359 | DEBUGFS_FWSTATS_DEL(pwr, tx_without_ps); | ||
| 360 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_beacons); | ||
| 361 | DEBUGFS_FWSTATS_DEL(pwr, power_save_off); | ||
| 362 | DEBUGFS_FWSTATS_DEL(pwr, enable_ps); | ||
| 363 | DEBUGFS_FWSTATS_DEL(pwr, disable_ps); | ||
| 364 | DEBUGFS_FWSTATS_DEL(pwr, fix_tsf_ps); | ||
| 365 | /* skipping cont_miss_bcns_spread for now */ | ||
| 366 | DEBUGFS_FWSTATS_DEL(pwr, rcvd_awake_beacons); | ||
| 367 | |||
| 368 | DEBUGFS_FWSTATS_DEL(mic, rx_pkts); | ||
| 369 | DEBUGFS_FWSTATS_DEL(mic, calc_failure); | ||
| 370 | |||
| 371 | DEBUGFS_FWSTATS_DEL(aes, encrypt_fail); | ||
| 372 | DEBUGFS_FWSTATS_DEL(aes, decrypt_fail); | ||
| 373 | DEBUGFS_FWSTATS_DEL(aes, encrypt_packets); | ||
| 374 | DEBUGFS_FWSTATS_DEL(aes, decrypt_packets); | ||
| 375 | DEBUGFS_FWSTATS_DEL(aes, encrypt_interrupt); | ||
| 376 | DEBUGFS_FWSTATS_DEL(aes, decrypt_interrupt); | ||
| 377 | |||
| 378 | DEBUGFS_FWSTATS_DEL(event, heart_beat); | ||
| 379 | DEBUGFS_FWSTATS_DEL(event, calibration); | ||
| 380 | DEBUGFS_FWSTATS_DEL(event, rx_mismatch); | ||
| 381 | DEBUGFS_FWSTATS_DEL(event, rx_mem_empty); | ||
| 382 | DEBUGFS_FWSTATS_DEL(event, rx_pool); | ||
| 383 | DEBUGFS_FWSTATS_DEL(event, oom_late); | ||
| 384 | DEBUGFS_FWSTATS_DEL(event, phy_transmit_error); | ||
| 385 | DEBUGFS_FWSTATS_DEL(event, tx_stuck); | ||
| 386 | |||
| 387 | DEBUGFS_FWSTATS_DEL(ps, pspoll_timeouts); | ||
| 388 | DEBUGFS_FWSTATS_DEL(ps, upsd_timeouts); | ||
| 389 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_sptime); | ||
| 390 | DEBUGFS_FWSTATS_DEL(ps, upsd_max_apturn); | ||
| 391 | DEBUGFS_FWSTATS_DEL(ps, pspoll_max_apturn); | ||
| 392 | DEBUGFS_FWSTATS_DEL(ps, pspoll_utilization); | ||
| 393 | DEBUGFS_FWSTATS_DEL(ps, upsd_utilization); | ||
| 394 | |||
| 395 | DEBUGFS_FWSTATS_DEL(rxpipe, rx_prep_beacon_drop); | ||
| 396 | DEBUGFS_FWSTATS_DEL(rxpipe, descr_host_int_trig_rx_data); | ||
| 397 | DEBUGFS_FWSTATS_DEL(rxpipe, beacon_buffer_thres_host_int_trig_rx_data); | ||
| 398 | DEBUGFS_FWSTATS_DEL(rxpipe, missed_beacon_host_int_trig_rx_data); | ||
| 399 | DEBUGFS_FWSTATS_DEL(rxpipe, tx_xfr_host_int_trig_rx_data); | ||
| 400 | |||
| 401 | DEBUGFS_DEL(tx_queue_len); | ||
| 402 | DEBUGFS_DEL(retry_count); | ||
| 403 | DEBUGFS_DEL(excessive_retries); | ||
| 404 | |||
| 405 | DEBUGFS_DEL(gpio_power); | ||
| 406 | } | ||
| 407 | |||
| 408 | static int wl1271_debugfs_add_files(struct wl1271 *wl) | 296 | static int wl1271_debugfs_add_files(struct wl1271 *wl) |
| 409 | { | 297 | { |
| 410 | int ret = 0; | 298 | int ret = 0; |
| 299 | struct dentry *entry, *stats; | ||
| 300 | |||
| 301 | stats = debugfs_create_dir("fw-statistics", wl->rootdir); | ||
| 302 | if (!stats || IS_ERR(stats)) { | ||
| 303 | entry = stats; | ||
| 304 | goto err; | ||
| 305 | } | ||
| 411 | 306 | ||
| 412 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); | 307 | DEBUGFS_FWSTATS_ADD(tx, internal_desc_overflow); |
| 413 | 308 | ||
| @@ -500,21 +395,33 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) | |||
| 500 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); | 395 | DEBUGFS_FWSTATS_ADD(rxpipe, missed_beacon_host_int_trig_rx_data); |
| 501 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); | 396 | DEBUGFS_FWSTATS_ADD(rxpipe, tx_xfr_host_int_trig_rx_data); |
| 502 | 397 | ||
| 503 | DEBUGFS_ADD(tx_queue_len, wl->debugfs.rootdir); | 398 | DEBUGFS_ADD(tx_queue_len, wl->rootdir); |
| 504 | DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | 399 | DEBUGFS_ADD(retry_count, wl->rootdir); |
| 505 | DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | 400 | DEBUGFS_ADD(excessive_retries, wl->rootdir); |
| 506 | 401 | ||
| 507 | DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); | 402 | DEBUGFS_ADD(gpio_power, wl->rootdir); |
| 508 | 403 | ||
| 509 | out: | 404 | entry = debugfs_create_x32("debug_level", 0600, wl->rootdir, |
| 510 | if (ret < 0) | 405 | &wl12xx_debug_level); |
| 511 | wl1271_debugfs_delete_files(wl); | 406 | if (!entry || IS_ERR(entry)) |
| 407 | goto err; | ||
| 408 | |||
| 409 | return 0; | ||
| 410 | |||
| 411 | err: | ||
| 412 | if (IS_ERR(entry)) | ||
| 413 | ret = PTR_ERR(entry); | ||
| 414 | else | ||
| 415 | ret = -ENOMEM; | ||
| 512 | 416 | ||
| 513 | return ret; | 417 | return ret; |
| 514 | } | 418 | } |
| 515 | 419 | ||
| 516 | void wl1271_debugfs_reset(struct wl1271 *wl) | 420 | void wl1271_debugfs_reset(struct wl1271 *wl) |
| 517 | { | 421 | { |
| 422 | if (!wl->rootdir) | ||
| 423 | return; | ||
| 424 | |||
| 518 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); | 425 | memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); |
| 519 | wl->stats.retry_count = 0; | 426 | wl->stats.retry_count = 0; |
| 520 | wl->stats.excessive_retries = 0; | 427 | wl->stats.excessive_retries = 0; |
| @@ -524,23 +431,15 @@ int wl1271_debugfs_init(struct wl1271 *wl) | |||
| 524 | { | 431 | { |
| 525 | int ret; | 432 | int ret; |
| 526 | 433 | ||
| 527 | wl->debugfs.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | 434 | wl->rootdir = debugfs_create_dir(KBUILD_MODNAME, |
| 435 | wl->hw->wiphy->debugfsdir); | ||
| 528 | 436 | ||
| 529 | if (IS_ERR(wl->debugfs.rootdir)) { | 437 | if (IS_ERR(wl->rootdir)) { |
| 530 | ret = PTR_ERR(wl->debugfs.rootdir); | 438 | ret = PTR_ERR(wl->rootdir); |
| 531 | wl->debugfs.rootdir = NULL; | 439 | wl->rootdir = NULL; |
| 532 | goto err; | 440 | goto err; |
| 533 | } | 441 | } |
| 534 | 442 | ||
| 535 | wl->debugfs.fw_statistics = debugfs_create_dir("fw-statistics", | ||
| 536 | wl->debugfs.rootdir); | ||
| 537 | |||
| 538 | if (IS_ERR(wl->debugfs.fw_statistics)) { | ||
| 539 | ret = PTR_ERR(wl->debugfs.fw_statistics); | ||
| 540 | wl->debugfs.fw_statistics = NULL; | ||
| 541 | goto err_root; | ||
| 542 | } | ||
| 543 | |||
| 544 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), | 443 | wl->stats.fw_stats = kzalloc(sizeof(*wl->stats.fw_stats), |
| 545 | GFP_KERNEL); | 444 | GFP_KERNEL); |
| 546 | 445 | ||
| @@ -563,12 +462,8 @@ err_file: | |||
| 563 | wl->stats.fw_stats = NULL; | 462 | wl->stats.fw_stats = NULL; |
| 564 | 463 | ||
| 565 | err_fw: | 464 | err_fw: |
| 566 | debugfs_remove(wl->debugfs.fw_statistics); | 465 | debugfs_remove_recursive(wl->rootdir); |
| 567 | wl->debugfs.fw_statistics = NULL; | 466 | wl->rootdir = NULL; |
| 568 | |||
| 569 | err_root: | ||
| 570 | debugfs_remove(wl->debugfs.rootdir); | ||
| 571 | wl->debugfs.rootdir = NULL; | ||
| 572 | 467 | ||
| 573 | err: | 468 | err: |
| 574 | return ret; | 469 | return ret; |
| @@ -576,15 +471,10 @@ err: | |||
| 576 | 471 | ||
| 577 | void wl1271_debugfs_exit(struct wl1271 *wl) | 472 | void wl1271_debugfs_exit(struct wl1271 *wl) |
| 578 | { | 473 | { |
| 579 | wl1271_debugfs_delete_files(wl); | ||
| 580 | |||
| 581 | kfree(wl->stats.fw_stats); | 474 | kfree(wl->stats.fw_stats); |
| 582 | wl->stats.fw_stats = NULL; | 475 | wl->stats.fw_stats = NULL; |
| 583 | 476 | ||
| 584 | debugfs_remove(wl->debugfs.fw_statistics); | 477 | debugfs_remove_recursive(wl->rootdir); |
| 585 | wl->debugfs.fw_statistics = NULL; | 478 | wl->rootdir = NULL; |
| 586 | |||
| 587 | debugfs_remove(wl->debugfs.rootdir); | ||
| 588 | wl->debugfs.rootdir = NULL; | ||
| 589 | 479 | ||
| 590 | } | 480 | } |
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 7949d346aadb..785a5304bfc4 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c | |||
| @@ -53,18 +53,16 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl) | |||
| 53 | int wl1271_init_templates_config(struct wl1271 *wl) | 53 | int wl1271_init_templates_config(struct wl1271 *wl) |
| 54 | { | 54 | { |
| 55 | int ret, i; | 55 | int ret, i; |
| 56 | size_t size; | ||
| 57 | 56 | ||
| 58 | /* send empty templates for fw memory reservation */ | 57 | /* send empty templates for fw memory reservation */ |
| 59 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | 58 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, |
| 60 | sizeof(struct wl12xx_probe_req_template), | 59 | WL1271_CMD_TEMPL_MAX_SIZE, |
| 61 | 0, WL1271_RATE_AUTOMATIC); | 60 | 0, WL1271_RATE_AUTOMATIC); |
| 62 | if (ret < 0) | 61 | if (ret < 0) |
| 63 | return ret; | 62 | return ret; |
| 64 | 63 | ||
| 65 | size = sizeof(struct wl12xx_probe_req_template); | ||
| 66 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | 64 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, |
| 67 | NULL, size, 0, | 65 | NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, |
| 68 | WL1271_RATE_AUTOMATIC); | 66 | WL1271_RATE_AUTOMATIC); |
| 69 | if (ret < 0) | 67 | if (ret < 0) |
| 70 | return ret; | 68 | return ret; |
| @@ -102,6 +100,13 @@ int wl1271_init_templates_config(struct wl1271 *wl) | |||
| 102 | if (ret < 0) | 100 | if (ret < 0) |
| 103 | return ret; | 101 | return ret; |
| 104 | 102 | ||
| 103 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL, | ||
| 104 | sizeof | ||
| 105 | (struct wl12xx_arp_rsp_template), | ||
| 106 | 0, WL1271_RATE_AUTOMATIC); | ||
| 107 | if (ret < 0) | ||
| 108 | return ret; | ||
| 109 | |||
| 105 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | 110 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { |
| 106 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, | 111 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, |
| 107 | WL1271_CMD_TEMPL_MAX_SIZE, i, | 112 | WL1271_CMD_TEMPL_MAX_SIZE, i, |
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index 35c2f1aca6ba..d557f73e7c19 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c | |||
| @@ -113,6 +113,7 @@ int wl1271_set_partition(struct wl1271 *wl, | |||
| 113 | 113 | ||
| 114 | return 0; | 114 | return 0; |
| 115 | } | 115 | } |
| 116 | EXPORT_SYMBOL_GPL(wl1271_set_partition); | ||
| 116 | 117 | ||
| 117 | void wl1271_io_reset(struct wl1271 *wl) | 118 | void wl1271_io_reset(struct wl1271 *wl) |
| 118 | { | 119 | { |
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 708ffe304c6d..062247ef3ad2 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
| @@ -336,7 +336,8 @@ out: | |||
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | static int wl1271_reg_notify(struct wiphy *wiphy, | 338 | static int wl1271_reg_notify(struct wiphy *wiphy, |
| 339 | struct regulatory_request *request) { | 339 | struct regulatory_request *request) |
| 340 | { | ||
| 340 | struct ieee80211_supported_band *band; | 341 | struct ieee80211_supported_band *band; |
| 341 | struct ieee80211_channel *ch; | 342 | struct ieee80211_channel *ch; |
| 342 | int i; | 343 | int i; |
| @@ -569,7 +570,7 @@ static void wl1271_irq_work(struct work_struct *work) | |||
| 569 | 570 | ||
| 570 | /* Check if any tx blocks were freed */ | 571 | /* Check if any tx blocks were freed */ |
| 571 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && | 572 | if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && |
| 572 | !skb_queue_empty(&wl->tx_queue)) { | 573 | wl->tx_queue_count) { |
| 573 | /* | 574 | /* |
| 574 | * In order to avoid starvation of the TX path, | 575 | * In order to avoid starvation of the TX path, |
| 575 | * call the work function directly. | 576 | * call the work function directly. |
| @@ -890,6 +891,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 890 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); | 891 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); |
| 891 | struct ieee80211_sta *sta = txinfo->control.sta; | 892 | struct ieee80211_sta *sta = txinfo->control.sta; |
| 892 | unsigned long flags; | 893 | unsigned long flags; |
| 894 | int q; | ||
| 893 | 895 | ||
| 894 | /* | 896 | /* |
| 895 | * peek into the rates configured in the STA entry. | 897 | * peek into the rates configured in the STA entry. |
| @@ -917,10 +919,12 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 917 | set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); | 919 | set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); |
| 918 | } | 920 | } |
| 919 | #endif | 921 | #endif |
| 922 | wl->tx_queue_count++; | ||
| 920 | spin_unlock_irqrestore(&wl->wl_lock, flags); | 923 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
| 921 | 924 | ||
| 922 | /* queue the packet */ | 925 | /* queue the packet */ |
| 923 | skb_queue_tail(&wl->tx_queue, skb); | 926 | q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
| 927 | skb_queue_tail(&wl->tx_queue[q], skb); | ||
| 924 | 928 | ||
| 925 | /* | 929 | /* |
| 926 | * The chip specific setup must run before the first TX packet - | 930 | * The chip specific setup must run before the first TX packet - |
| @@ -934,7 +938,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 934 | * The workqueue is slow to process the tx_queue and we need stop | 938 | * The workqueue is slow to process the tx_queue and we need stop |
| 935 | * the queue here, otherwise the queue will get too long. | 939 | * the queue here, otherwise the queue will get too long. |
| 936 | */ | 940 | */ |
| 937 | if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) { | 941 | if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) { |
| 938 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); | 942 | wl1271_debug(DEBUG_TX, "op_tx: stopping queues"); |
| 939 | 943 | ||
| 940 | spin_lock_irqsave(&wl->wl_lock, flags); | 944 | spin_lock_irqsave(&wl->wl_lock, flags); |
| @@ -1064,6 +1068,16 @@ power_off: | |||
| 1064 | strncpy(wiphy->fw_version, wl->chip.fw_ver, | 1068 | strncpy(wiphy->fw_version, wl->chip.fw_ver, |
| 1065 | sizeof(wiphy->fw_version)); | 1069 | sizeof(wiphy->fw_version)); |
| 1066 | 1070 | ||
| 1071 | /* | ||
| 1072 | * Now we know if 11a is supported (info from the NVS), so disable | ||
| 1073 | * 11a channels if not supported | ||
| 1074 | */ | ||
| 1075 | if (!wl->enable_11a) | ||
| 1076 | wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0; | ||
| 1077 | |||
| 1078 | wl1271_debug(DEBUG_MAC80211, "11a is %ssupported", | ||
| 1079 | wl->enable_11a ? "" : "not "); | ||
| 1080 | |||
| 1067 | out: | 1081 | out: |
| 1068 | mutex_unlock(&wl->mutex); | 1082 | mutex_unlock(&wl->mutex); |
| 1069 | 1083 | ||
| @@ -1157,10 +1171,16 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | |||
| 1157 | struct wl1271 *wl = hw->priv; | 1171 | struct wl1271 *wl = hw->priv; |
| 1158 | 1172 | ||
| 1159 | mutex_lock(&wl->mutex); | 1173 | mutex_lock(&wl->mutex); |
| 1160 | WARN_ON(wl->vif != vif); | 1174 | /* |
| 1161 | __wl1271_op_remove_interface(wl); | 1175 | * wl->vif can be null here if someone shuts down the interface |
| 1162 | mutex_unlock(&wl->mutex); | 1176 | * just when hardware recovery has been started. |
| 1177 | */ | ||
| 1178 | if (wl->vif) { | ||
| 1179 | WARN_ON(wl->vif != vif); | ||
| 1180 | __wl1271_op_remove_interface(wl); | ||
| 1181 | } | ||
| 1163 | 1182 | ||
| 1183 | mutex_unlock(&wl->mutex); | ||
| 1164 | cancel_work_sync(&wl->recovery_work); | 1184 | cancel_work_sync(&wl->recovery_work); |
| 1165 | } | 1185 | } |
| 1166 | 1186 | ||
| @@ -1801,21 +1821,21 @@ out: | |||
| 1801 | return ret; | 1821 | return ret; |
| 1802 | } | 1822 | } |
| 1803 | 1823 | ||
| 1804 | static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon) | 1824 | static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, |
| 1825 | int offset) | ||
| 1805 | { | 1826 | { |
| 1806 | u8 *ptr = beacon->data + | 1827 | u8 *ptr = skb->data + offset; |
| 1807 | offsetof(struct ieee80211_mgmt, u.beacon.variable); | ||
| 1808 | 1828 | ||
| 1809 | /* find the location of the ssid in the beacon */ | 1829 | /* find the location of the ssid in the beacon */ |
| 1810 | while (ptr < beacon->data + beacon->len) { | 1830 | while (ptr < skb->data + skb->len) { |
| 1811 | if (ptr[0] == WLAN_EID_SSID) { | 1831 | if (ptr[0] == WLAN_EID_SSID) { |
| 1812 | wl->ssid_len = ptr[1]; | 1832 | wl->ssid_len = ptr[1]; |
| 1813 | memcpy(wl->ssid, ptr+2, wl->ssid_len); | 1833 | memcpy(wl->ssid, ptr+2, wl->ssid_len); |
| 1814 | return; | 1834 | return; |
| 1815 | } | 1835 | } |
| 1816 | ptr += ptr[1]; | 1836 | ptr += (ptr[1] + 2); |
| 1817 | } | 1837 | } |
| 1818 | wl1271_error("ad-hoc beacon template has no SSID!\n"); | 1838 | wl1271_error("No SSID in IEs!\n"); |
| 1819 | } | 1839 | } |
| 1820 | 1840 | ||
| 1821 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | 1841 | static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, |
| @@ -1858,8 +1878,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1858 | 1878 | ||
| 1859 | if (beacon) { | 1879 | if (beacon) { |
| 1860 | struct ieee80211_hdr *hdr; | 1880 | struct ieee80211_hdr *hdr; |
| 1881 | int ieoffset = offsetof(struct ieee80211_mgmt, | ||
| 1882 | u.beacon.variable); | ||
| 1883 | |||
| 1884 | wl1271_ssid_set(wl, beacon, ieoffset); | ||
| 1861 | 1885 | ||
| 1862 | wl1271_ssid_set(wl, beacon); | ||
| 1863 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | 1886 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, |
| 1864 | beacon->data, | 1887 | beacon->data, |
| 1865 | beacon->len, 0, | 1888 | beacon->len, 0, |
| @@ -1939,6 +1962,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1939 | if (changed & BSS_CHANGED_ASSOC) { | 1962 | if (changed & BSS_CHANGED_ASSOC) { |
| 1940 | if (bss_conf->assoc) { | 1963 | if (bss_conf->assoc) { |
| 1941 | u32 rates; | 1964 | u32 rates; |
| 1965 | int ieoffset; | ||
| 1942 | wl->aid = bss_conf->aid; | 1966 | wl->aid = bss_conf->aid; |
| 1943 | set_assoc = true; | 1967 | set_assoc = true; |
| 1944 | 1968 | ||
| @@ -1967,13 +1991,13 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1967 | goto out_sleep; | 1991 | goto out_sleep; |
| 1968 | 1992 | ||
| 1969 | /* | 1993 | /* |
| 1970 | * The SSID is intentionally set to NULL here - the | 1994 | * Get a template for hardware connection maintenance |
| 1971 | * firmware will set the probe request with a | ||
| 1972 | * broadcast SSID regardless of what we set in the | ||
| 1973 | * template. | ||
| 1974 | */ | 1995 | */ |
| 1975 | ret = wl1271_cmd_build_probe_req(wl, NULL, 0, | 1996 | dev_kfree_skb(wl->probereq); |
| 1976 | NULL, 0, wl->band); | 1997 | wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL); |
| 1998 | ieoffset = offsetof(struct ieee80211_mgmt, | ||
| 1999 | u.probe_req.variable); | ||
| 2000 | wl1271_ssid_set(wl, wl->probereq, ieoffset); | ||
| 1977 | 2001 | ||
| 1978 | /* enable the connection monitoring feature */ | 2002 | /* enable the connection monitoring feature */ |
| 1979 | ret = wl1271_acx_conn_monit_params(wl, true); | 2003 | ret = wl1271_acx_conn_monit_params(wl, true); |
| @@ -1996,6 +2020,10 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
| 1996 | clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); | 2020 | clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); |
| 1997 | wl->aid = 0; | 2021 | wl->aid = 0; |
| 1998 | 2022 | ||
| 2023 | /* free probe-request template */ | ||
| 2024 | dev_kfree_skb(wl->probereq); | ||
| 2025 | wl->probereq = NULL; | ||
| 2026 | |||
| 1999 | /* re-enable dynamic ps - just in case */ | 2027 | /* re-enable dynamic ps - just in case */ |
| 2000 | ieee80211_enable_dyn_ps(wl->vif); | 2028 | ieee80211_enable_dyn_ps(wl->vif); |
| 2001 | 2029 | ||
| @@ -2085,10 +2113,26 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
| 2085 | __be32 addr = bss_conf->arp_addr_list[0]; | 2113 | __be32 addr = bss_conf->arp_addr_list[0]; |
| 2086 | WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); | 2114 | WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); |
| 2087 | 2115 | ||
| 2088 | if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled) | 2116 | if (bss_conf->arp_addr_cnt == 1 && |
| 2089 | ret = wl1271_acx_arp_ip_filter(wl, true, addr); | 2117 | bss_conf->arp_filter_enabled) { |
| 2090 | else | 2118 | /* |
| 2091 | ret = wl1271_acx_arp_ip_filter(wl, false, addr); | 2119 | * The template should have been configured only upon |
| 2120 | * association. however, it seems that the correct ip | ||
| 2121 | * isn't being set (when sending), so we have to | ||
| 2122 | * reconfigure the template upon every ip change. | ||
| 2123 | */ | ||
| 2124 | ret = wl1271_cmd_build_arp_rsp(wl, addr); | ||
| 2125 | if (ret < 0) { | ||
| 2126 | wl1271_warning("build arp rsp failed: %d", ret); | ||
| 2127 | goto out_sleep; | ||
| 2128 | } | ||
| 2129 | |||
| 2130 | ret = wl1271_acx_arp_ip_filter(wl, | ||
| 2131 | (ACX_ARP_FILTER_ARP_FILTERING | | ||
| 2132 | ACX_ARP_FILTER_AUTO_ARP), | ||
| 2133 | addr); | ||
| 2134 | } else | ||
| 2135 | ret = wl1271_acx_arp_ip_filter(wl, 0, addr); | ||
| 2092 | 2136 | ||
| 2093 | if (ret < 0) | 2137 | if (ret < 0) |
| 2094 | goto out_sleep; | 2138 | goto out_sleep; |
| @@ -2353,14 +2397,6 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = { | |||
| 2353 | 2397 | ||
| 2354 | /* 5 GHz band channels for WL1273 */ | 2398 | /* 5 GHz band channels for WL1273 */ |
| 2355 | static struct ieee80211_channel wl1271_channels_5ghz[] = { | 2399 | static struct ieee80211_channel wl1271_channels_5ghz[] = { |
| 2356 | { .hw_value = 183, .center_freq = 4915}, | ||
| 2357 | { .hw_value = 184, .center_freq = 4920}, | ||
| 2358 | { .hw_value = 185, .center_freq = 4925}, | ||
| 2359 | { .hw_value = 187, .center_freq = 4935}, | ||
| 2360 | { .hw_value = 188, .center_freq = 4940}, | ||
| 2361 | { .hw_value = 189, .center_freq = 4945}, | ||
| 2362 | { .hw_value = 192, .center_freq = 4960}, | ||
| 2363 | { .hw_value = 196, .center_freq = 4980}, | ||
| 2364 | { .hw_value = 7, .center_freq = 5035}, | 2400 | { .hw_value = 7, .center_freq = 5035}, |
| 2365 | { .hw_value = 8, .center_freq = 5040}, | 2401 | { .hw_value = 8, .center_freq = 5040}, |
| 2366 | { .hw_value = 9, .center_freq = 5045}, | 2402 | { .hw_value = 9, .center_freq = 5045}, |
| @@ -2581,6 +2617,8 @@ int wl1271_register_hw(struct wl1271 *wl) | |||
| 2581 | 2617 | ||
| 2582 | wl->mac80211_registered = true; | 2618 | wl->mac80211_registered = true; |
| 2583 | 2619 | ||
| 2620 | wl1271_debugfs_init(wl); | ||
| 2621 | |||
| 2584 | register_netdevice_notifier(&wl1271_dev_notifier); | 2622 | register_netdevice_notifier(&wl1271_dev_notifier); |
| 2585 | 2623 | ||
| 2586 | wl1271_notice("loaded"); | 2624 | wl1271_notice("loaded"); |
| @@ -2631,6 +2669,13 @@ int wl1271_init_ieee80211(struct wl1271 *wl) | |||
| 2631 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 2669 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
| 2632 | BIT(NL80211_IFTYPE_ADHOC); | 2670 | BIT(NL80211_IFTYPE_ADHOC); |
| 2633 | wl->hw->wiphy->max_scan_ssids = 1; | 2671 | wl->hw->wiphy->max_scan_ssids = 1; |
| 2672 | /* | ||
| 2673 | * Maximum length of elements in scanning probe request templates | ||
| 2674 | * should be the maximum length possible for a template, without | ||
| 2675 | * the IEEE80211 header of the template | ||
| 2676 | */ | ||
| 2677 | wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - | ||
| 2678 | sizeof(struct ieee80211_header); | ||
| 2634 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; | 2679 | wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; |
| 2635 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; | 2680 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; |
| 2636 | 2681 | ||
| @@ -2677,7 +2722,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
| 2677 | wl->hw = hw; | 2722 | wl->hw = hw; |
| 2678 | wl->plat_dev = plat_dev; | 2723 | wl->plat_dev = plat_dev; |
| 2679 | 2724 | ||
| 2680 | skb_queue_head_init(&wl->tx_queue); | 2725 | for (i = 0; i < NUM_TX_QUEUES; i++) |
| 2726 | skb_queue_head_init(&wl->tx_queue[i]); | ||
| 2681 | 2727 | ||
| 2682 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); | 2728 | INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); |
| 2683 | INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); | 2729 | INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work); |
| @@ -2715,8 +2761,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
| 2715 | /* Apply default driver configuration. */ | 2761 | /* Apply default driver configuration. */ |
| 2716 | wl1271_conf_init(wl); | 2762 | wl1271_conf_init(wl); |
| 2717 | 2763 | ||
| 2718 | wl1271_debugfs_init(wl); | ||
| 2719 | |||
| 2720 | order = get_order(WL1271_AGGR_BUFFER_SIZE); | 2764 | order = get_order(WL1271_AGGR_BUFFER_SIZE); |
| 2721 | wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); | 2765 | wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); |
| 2722 | if (!wl->aggr_buf) { | 2766 | if (!wl->aggr_buf) { |
| @@ -2793,6 +2837,11 @@ int wl1271_free_hw(struct wl1271 *wl) | |||
| 2793 | } | 2837 | } |
| 2794 | EXPORT_SYMBOL_GPL(wl1271_free_hw); | 2838 | EXPORT_SYMBOL_GPL(wl1271_free_hw); |
| 2795 | 2839 | ||
| 2840 | u32 wl12xx_debug_level; | ||
| 2841 | EXPORT_SYMBOL_GPL(wl12xx_debug_level); | ||
| 2842 | module_param_named(debug_level, wl12xx_debug_level, uint, DEBUG_NONE); | ||
| 2843 | MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); | ||
| 2844 | |||
| 2796 | MODULE_LICENSE("GPL"); | 2845 | MODULE_LICENSE("GPL"); |
| 2797 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); | 2846 | MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>"); |
| 2798 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); | 2847 | MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); |
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index f3f2c5b011ee..6f897b9d90ca 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c | |||
| @@ -51,6 +51,10 @@ void wl1271_scan_complete_work(struct work_struct *work) | |||
| 51 | wl->scan.req = NULL; | 51 | wl->scan.req = NULL; |
| 52 | ieee80211_scan_completed(wl->hw, false); | 52 | ieee80211_scan_completed(wl->hw, false); |
| 53 | 53 | ||
| 54 | /* restore hardware connection monitoring template */ | ||
| 55 | if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) | ||
| 56 | wl1271_cmd_build_ap_probe_req(wl, wl->probereq); | ||
| 57 | |||
| 54 | if (wl->scan.failed) { | 58 | if (wl->scan.failed) { |
| 55 | wl1271_info("Scan completed due to error."); | 59 | wl1271_info("Scan completed due to error."); |
| 56 | ieee80211_queue_work(wl->hw, &wl->recovery_work); | 60 | ieee80211_queue_work(wl->hw, &wl->recovery_work); |
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c new file mode 100644 index 000000000000..9fcbd3dd8490 --- /dev/null +++ b/drivers/net/wireless/wl12xx/sdio_test.c | |||
| @@ -0,0 +1,520 @@ | |||
| 1 | /* | ||
| 2 | * SDIO testing driver for wl12xx | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Nokia Corporation | ||
| 5 | * | ||
| 6 | * Contact: Roger Quadros <roger.quadros@nokia.com> | ||
| 7 | * | ||
| 8 | * wl12xx read/write routines taken from the main module | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * version 2 as published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 22 | * 02110-1301 USA | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/irq.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/crc7.h> | ||
| 29 | #include <linux/vmalloc.h> | ||
| 30 | #include <linux/mmc/sdio_func.h> | ||
| 31 | #include <linux/mmc/sdio_ids.h> | ||
| 32 | #include <linux/mmc/card.h> | ||
| 33 | #include <linux/gpio.h> | ||
| 34 | #include <linux/wl12xx.h> | ||
| 35 | #include <linux/kthread.h> | ||
| 36 | #include <linux/firmware.h> | ||
| 37 | #include <linux/pm_runtime.h> | ||
| 38 | |||
| 39 | #include "wl12xx.h" | ||
| 40 | #include "io.h" | ||
| 41 | #include "boot.h" | ||
| 42 | |||
| 43 | #ifndef SDIO_VENDOR_ID_TI | ||
| 44 | #define SDIO_VENDOR_ID_TI 0x0097 | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #ifndef SDIO_DEVICE_ID_TI_WL1271 | ||
| 48 | #define SDIO_DEVICE_ID_TI_WL1271 0x4076 | ||
| 49 | #endif | ||
| 50 | |||
| 51 | static bool rx, tx; | ||
| 52 | |||
| 53 | module_param(rx, bool, S_IRUGO | S_IWUSR); | ||
| 54 | MODULE_PARM_DESC(rx, "Perform rx test. Default (0). " | ||
| 55 | "This test continuously reads data from the SDIO device.\n"); | ||
| 56 | |||
| 57 | module_param(tx, bool, S_IRUGO | S_IWUSR); | ||
| 58 | MODULE_PARM_DESC(tx, "Perform tx test. Default (0). " | ||
| 59 | "This test continuously writes data to the SDIO device.\n"); | ||
| 60 | |||
| 61 | struct wl1271_test { | ||
| 62 | struct wl1271 wl; | ||
| 63 | struct task_struct *test_task; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static const struct sdio_device_id wl1271_devices[] = { | ||
| 67 | { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) }, | ||
| 68 | {} | ||
| 69 | }; | ||
| 70 | |||
| 71 | static inline struct sdio_func *wl_to_func(struct wl1271 *wl) | ||
| 72 | { | ||
| 73 | return wl->if_priv; | ||
| 74 | } | ||
| 75 | |||
| 76 | static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl) | ||
| 77 | { | ||
| 78 | return &(wl_to_func(wl)->dev); | ||
| 79 | } | ||
| 80 | |||
| 81 | static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, | ||
| 82 | size_t len, bool fixed) | ||
| 83 | { | ||
| 84 | int ret = 0; | ||
| 85 | struct sdio_func *func = wl_to_func(wl); | ||
| 86 | |||
| 87 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | ||
| 88 | ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); | ||
| 89 | wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", | ||
| 90 | addr, ((u8 *)buf)[0]); | ||
| 91 | } else { | ||
| 92 | if (fixed) | ||
| 93 | ret = sdio_readsb(func, buf, addr, len); | ||
| 94 | else | ||
| 95 | ret = sdio_memcpy_fromio(func, buf, addr, len); | ||
| 96 | |||
| 97 | wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", | ||
| 98 | addr, len); | ||
| 99 | wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); | ||
| 100 | } | ||
| 101 | |||
| 102 | if (ret) | ||
| 103 | wl1271_error("sdio read failed (%d)", ret); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, | ||
| 107 | size_t len, bool fixed) | ||
| 108 | { | ||
| 109 | int ret = 0; | ||
| 110 | struct sdio_func *func = wl_to_func(wl); | ||
| 111 | |||
| 112 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | ||
| 113 | sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); | ||
| 114 | wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", | ||
| 115 | addr, ((u8 *)buf)[0]); | ||
| 116 | } else { | ||
| 117 | wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes", | ||
| 118 | addr, len); | ||
| 119 | wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); | ||
| 120 | |||
| 121 | if (fixed) | ||
| 122 | ret = sdio_writesb(func, addr, buf, len); | ||
| 123 | else | ||
| 124 | ret = sdio_memcpy_toio(func, addr, buf, len); | ||
| 125 | } | ||
| 126 | if (ret) | ||
| 127 | wl1271_error("sdio write failed (%d)", ret); | ||
| 128 | |||
| 129 | } | ||
| 130 | |||
| 131 | static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) | ||
| 132 | { | ||
| 133 | struct sdio_func *func = wl_to_func(wl); | ||
| 134 | int ret; | ||
| 135 | |||
| 136 | /* Let the SDIO stack handle wlan_enable control, so we | ||
| 137 | * keep host claimed while wlan is in use to keep wl1271 | ||
| 138 | * alive. | ||
| 139 | */ | ||
| 140 | if (enable) { | ||
| 141 | /* Power up the card */ | ||
| 142 | ret = pm_runtime_get_sync(&func->dev); | ||
| 143 | if (ret < 0) | ||
| 144 | goto out; | ||
| 145 | sdio_claim_host(func); | ||
| 146 | sdio_enable_func(func); | ||
| 147 | sdio_release_host(func); | ||
| 148 | } else { | ||
| 149 | sdio_claim_host(func); | ||
| 150 | sdio_disable_func(func); | ||
| 151 | sdio_release_host(func); | ||
| 152 | |||
| 153 | /* Power down the card */ | ||
| 154 | ret = pm_runtime_put_sync(&func->dev); | ||
| 155 | } | ||
| 156 | |||
| 157 | out: | ||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void wl1271_sdio_disable_interrupts(struct wl1271 *wl) | ||
| 162 | { | ||
| 163 | } | ||
| 164 | |||
| 165 | static void wl1271_sdio_enable_interrupts(struct wl1271 *wl) | ||
| 166 | { | ||
| 167 | } | ||
| 168 | |||
| 169 | |||
| 170 | static struct wl1271_if_operations sdio_ops = { | ||
| 171 | .read = wl1271_sdio_raw_read, | ||
| 172 | .write = wl1271_sdio_raw_write, | ||
| 173 | .power = wl1271_sdio_set_power, | ||
| 174 | .dev = wl1271_sdio_wl_to_dev, | ||
| 175 | .enable_irq = wl1271_sdio_enable_interrupts, | ||
| 176 | .disable_irq = wl1271_sdio_disable_interrupts, | ||
| 177 | }; | ||
| 178 | |||
| 179 | static void wl1271_fw_wakeup(struct wl1271 *wl) | ||
| 180 | { | ||
| 181 | u32 elp_reg; | ||
| 182 | |||
| 183 | elp_reg = ELPCTRL_WAKE_UP; | ||
| 184 | wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int wl1271_fetch_firmware(struct wl1271 *wl) | ||
| 188 | { | ||
| 189 | const struct firmware *fw; | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); | ||
| 193 | |||
| 194 | if (ret < 0) { | ||
| 195 | wl1271_error("could not get firmware: %d", ret); | ||
| 196 | return ret; | ||
| 197 | } | ||
| 198 | |||
| 199 | if (fw->size % 4) { | ||
| 200 | wl1271_error("firmware size is not multiple of 32 bits: %zu", | ||
| 201 | fw->size); | ||
| 202 | ret = -EILSEQ; | ||
| 203 | goto out; | ||
| 204 | } | ||
| 205 | |||
| 206 | wl->fw_len = fw->size; | ||
| 207 | wl->fw = vmalloc(wl->fw_len); | ||
| 208 | |||
| 209 | if (!wl->fw) { | ||
| 210 | wl1271_error("could not allocate memory for the firmware"); | ||
| 211 | ret = -ENOMEM; | ||
| 212 | goto out; | ||
| 213 | } | ||
| 214 | |||
| 215 | memcpy(wl->fw, fw->data, wl->fw_len); | ||
| 216 | |||
| 217 | ret = 0; | ||
| 218 | |||
| 219 | out: | ||
| 220 | release_firmware(fw); | ||
| 221 | |||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int wl1271_fetch_nvs(struct wl1271 *wl) | ||
| 226 | { | ||
| 227 | const struct firmware *fw; | ||
| 228 | int ret; | ||
| 229 | |||
| 230 | ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); | ||
| 231 | |||
| 232 | if (ret < 0) { | ||
| 233 | wl1271_error("could not get nvs file: %d", ret); | ||
| 234 | return ret; | ||
| 235 | } | ||
| 236 | |||
| 237 | wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); | ||
| 238 | |||
| 239 | if (!wl->nvs) { | ||
| 240 | wl1271_error("could not allocate memory for the nvs file"); | ||
| 241 | ret = -ENOMEM; | ||
| 242 | goto out; | ||
| 243 | } | ||
| 244 | |||
| 245 | wl->nvs_len = fw->size; | ||
| 246 | |||
| 247 | out: | ||
| 248 | release_firmware(fw); | ||
| 249 | |||
| 250 | return ret; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int wl1271_chip_wakeup(struct wl1271 *wl) | ||
| 254 | { | ||
| 255 | struct wl1271_partition_set partition; | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | msleep(WL1271_PRE_POWER_ON_SLEEP); | ||
| 259 | ret = wl1271_power_on(wl); | ||
| 260 | if (ret) | ||
| 261 | return ret; | ||
| 262 | |||
| 263 | msleep(WL1271_POWER_ON_SLEEP); | ||
| 264 | |||
| 265 | /* We don't need a real memory partition here, because we only want | ||
| 266 | * to use the registers at this point. */ | ||
| 267 | memset(&partition, 0, sizeof(partition)); | ||
| 268 | partition.reg.start = REGISTERS_BASE; | ||
| 269 | partition.reg.size = REGISTERS_DOWN_SIZE; | ||
| 270 | wl1271_set_partition(wl, &partition); | ||
| 271 | |||
| 272 | /* ELP module wake up */ | ||
| 273 | wl1271_fw_wakeup(wl); | ||
| 274 | |||
| 275 | /* whal_FwCtrl_BootSm() */ | ||
| 276 | |||
| 277 | /* 0. read chip id from CHIP_ID */ | ||
| 278 | wl->chip.id = wl1271_read32(wl, CHIP_ID_B); | ||
| 279 | |||
| 280 | /* 1. check if chip id is valid */ | ||
| 281 | |||
| 282 | switch (wl->chip.id) { | ||
| 283 | case CHIP_ID_1271_PG10: | ||
| 284 | wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", | ||
| 285 | wl->chip.id); | ||
| 286 | break; | ||
| 287 | case CHIP_ID_1271_PG20: | ||
| 288 | wl1271_notice("chip id 0x%x (1271 PG20)", | ||
| 289 | wl->chip.id); | ||
| 290 | break; | ||
| 291 | default: | ||
| 292 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | ||
| 293 | return -ENODEV; | ||
| 294 | } | ||
| 295 | |||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | |||
| 299 | static struct wl1271_partition_set part_down = { | ||
| 300 | .mem = { | ||
| 301 | .start = 0x00000000, | ||
| 302 | .size = 0x000177c0 | ||
| 303 | }, | ||
| 304 | .reg = { | ||
| 305 | .start = REGISTERS_BASE, | ||
| 306 | .size = 0x00008800 | ||
| 307 | }, | ||
| 308 | .mem2 = { | ||
| 309 | .start = 0x00000000, | ||
| 310 | .size = 0x00000000 | ||
| 311 | }, | ||
| 312 | .mem3 = { | ||
| 313 | .start = 0x00000000, | ||
| 314 | .size = 0x00000000 | ||
| 315 | }, | ||
| 316 | }; | ||
| 317 | |||
| 318 | static int tester(void *data) | ||
| 319 | { | ||
| 320 | struct wl1271 *wl = data; | ||
| 321 | struct sdio_func *func = wl_to_func(wl); | ||
| 322 | struct device *pdev = &func->dev; | ||
| 323 | int ret = 0; | ||
| 324 | bool rx_started = 0; | ||
| 325 | bool tx_started = 0; | ||
| 326 | uint8_t *tx_buf, *rx_buf; | ||
| 327 | int test_size = PAGE_SIZE; | ||
| 328 | u32 addr = 0; | ||
| 329 | struct wl1271_partition_set partition; | ||
| 330 | |||
| 331 | /* We assume chip is powered up and firmware fetched */ | ||
| 332 | |||
| 333 | memcpy(&partition, &part_down, sizeof(partition)); | ||
| 334 | partition.mem.start = addr; | ||
| 335 | wl1271_set_partition(wl, &partition); | ||
| 336 | |||
| 337 | tx_buf = kmalloc(test_size, GFP_KERNEL); | ||
| 338 | rx_buf = kmalloc(test_size, GFP_KERNEL); | ||
| 339 | if (!tx_buf || !rx_buf) { | ||
| 340 | dev_err(pdev, | ||
| 341 | "Could not allocate memory. Test will not run.\n"); | ||
| 342 | ret = -ENOMEM; | ||
| 343 | goto free; | ||
| 344 | } | ||
| 345 | |||
| 346 | memset(tx_buf, 0x5a, test_size); | ||
| 347 | |||
| 348 | /* write something in data area so we can read it back */ | ||
| 349 | wl1271_write(wl, addr, tx_buf, test_size, false); | ||
| 350 | |||
| 351 | while (!kthread_should_stop()) { | ||
| 352 | if (rx && !rx_started) { | ||
| 353 | dev_info(pdev, "starting rx test\n"); | ||
| 354 | rx_started = 1; | ||
| 355 | } else if (!rx && rx_started) { | ||
| 356 | dev_info(pdev, "stopping rx test\n"); | ||
| 357 | rx_started = 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (tx && !tx_started) { | ||
| 361 | dev_info(pdev, "starting tx test\n"); | ||
| 362 | tx_started = 1; | ||
| 363 | } else if (!tx && tx_started) { | ||
| 364 | dev_info(pdev, "stopping tx test\n"); | ||
| 365 | tx_started = 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | if (rx_started) | ||
| 369 | wl1271_read(wl, addr, rx_buf, test_size, false); | ||
| 370 | |||
| 371 | if (tx_started) | ||
| 372 | wl1271_write(wl, addr, tx_buf, test_size, false); | ||
| 373 | |||
| 374 | if (!rx_started && !tx_started) | ||
| 375 | msleep(100); | ||
| 376 | } | ||
| 377 | |||
| 378 | free: | ||
| 379 | kfree(tx_buf); | ||
| 380 | kfree(rx_buf); | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 384 | static int __devinit wl1271_probe(struct sdio_func *func, | ||
| 385 | const struct sdio_device_id *id) | ||
| 386 | { | ||
| 387 | const struct wl12xx_platform_data *wlan_data; | ||
| 388 | struct wl1271 *wl; | ||
| 389 | struct wl1271_test *wl_test; | ||
| 390 | int ret = 0; | ||
| 391 | |||
| 392 | /* wl1271 has 2 sdio functions we handle just the wlan part */ | ||
| 393 | if (func->num != 0x02) | ||
| 394 | return -ENODEV; | ||
| 395 | |||
| 396 | wl_test = kzalloc(sizeof(struct wl1271_test), GFP_KERNEL); | ||
| 397 | if (!wl_test) { | ||
| 398 | dev_err(&func->dev, "Could not allocate memory\n"); | ||
| 399 | return -ENOMEM; | ||
| 400 | } | ||
| 401 | |||
| 402 | wl = &wl_test->wl; | ||
| 403 | |||
| 404 | wl->if_priv = func; | ||
| 405 | wl->if_ops = &sdio_ops; | ||
| 406 | |||
| 407 | /* Grab access to FN0 for ELP reg. */ | ||
| 408 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
| 409 | |||
| 410 | wlan_data = wl12xx_get_platform_data(); | ||
| 411 | if (IS_ERR(wlan_data)) { | ||
| 412 | ret = PTR_ERR(wlan_data); | ||
| 413 | dev_err(&func->dev, "missing wlan platform data: %d\n", ret); | ||
| 414 | goto out_free; | ||
| 415 | } | ||
| 416 | |||
| 417 | wl->irq = wlan_data->irq; | ||
| 418 | wl->ref_clock = wlan_data->board_ref_clock; | ||
| 419 | |||
| 420 | sdio_set_drvdata(func, wl_test); | ||
| 421 | |||
| 422 | |||
| 423 | /* power up the device */ | ||
| 424 | ret = wl1271_chip_wakeup(wl); | ||
| 425 | if (ret) { | ||
| 426 | dev_err(&func->dev, "could not wake up chip\n"); | ||
| 427 | goto out_free; | ||
| 428 | } | ||
| 429 | |||
| 430 | if (wl->fw == NULL) { | ||
| 431 | ret = wl1271_fetch_firmware(wl); | ||
| 432 | if (ret < 0) { | ||
| 433 | dev_err(&func->dev, "firmware fetch error\n"); | ||
| 434 | goto out_off; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | /* fetch NVS */ | ||
| 439 | if (wl->nvs == NULL) { | ||
| 440 | ret = wl1271_fetch_nvs(wl); | ||
| 441 | if (ret < 0) { | ||
| 442 | dev_err(&func->dev, "NVS fetch error\n"); | ||
| 443 | goto out_off; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | |||
| 447 | ret = wl1271_load_firmware(wl); | ||
| 448 | if (ret < 0) { | ||
| 449 | dev_err(&func->dev, "firmware load error: %d\n", ret); | ||
| 450 | goto out_free; | ||
| 451 | } | ||
| 452 | |||
| 453 | dev_info(&func->dev, "initialized\n"); | ||
| 454 | |||
| 455 | /* I/O testing will be done in the tester thread */ | ||
| 456 | |||
| 457 | wl_test->test_task = kthread_run(tester, wl, "sdio_tester"); | ||
| 458 | if (IS_ERR(wl_test->test_task)) { | ||
| 459 | dev_err(&func->dev, "unable to create kernel thread\n"); | ||
| 460 | ret = PTR_ERR(wl_test->test_task); | ||
| 461 | goto out_free; | ||
| 462 | } | ||
| 463 | |||
| 464 | return 0; | ||
| 465 | |||
| 466 | out_off: | ||
| 467 | /* power off the chip */ | ||
| 468 | wl1271_power_off(wl); | ||
| 469 | |||
| 470 | out_free: | ||
| 471 | kfree(wl_test); | ||
| 472 | return ret; | ||
| 473 | } | ||
| 474 | |||
| 475 | static void __devexit wl1271_remove(struct sdio_func *func) | ||
| 476 | { | ||
| 477 | struct wl1271_test *wl_test = sdio_get_drvdata(func); | ||
| 478 | |||
| 479 | /* stop the I/O test thread */ | ||
| 480 | kthread_stop(wl_test->test_task); | ||
| 481 | |||
| 482 | /* power off the chip */ | ||
| 483 | wl1271_power_off(&wl_test->wl); | ||
| 484 | |||
| 485 | vfree(wl_test->wl.fw); | ||
| 486 | wl_test->wl.fw = NULL; | ||
| 487 | kfree(wl_test->wl.nvs); | ||
| 488 | wl_test->wl.nvs = NULL; | ||
| 489 | |||
| 490 | kfree(wl_test); | ||
| 491 | } | ||
| 492 | |||
| 493 | static struct sdio_driver wl1271_sdio_driver = { | ||
| 494 | .name = "wl12xx_sdio_test", | ||
| 495 | .id_table = wl1271_devices, | ||
| 496 | .probe = wl1271_probe, | ||
| 497 | .remove = __devexit_p(wl1271_remove), | ||
| 498 | }; | ||
| 499 | |||
| 500 | static int __init wl1271_init(void) | ||
| 501 | { | ||
| 502 | int ret; | ||
| 503 | |||
| 504 | ret = sdio_register_driver(&wl1271_sdio_driver); | ||
| 505 | if (ret < 0) | ||
| 506 | pr_err("failed to register sdio driver: %d\n", ret); | ||
| 507 | |||
| 508 | return ret; | ||
| 509 | } | ||
| 510 | module_init(wl1271_init); | ||
| 511 | |||
| 512 | static void __exit wl1271_exit(void) | ||
| 513 | { | ||
| 514 | sdio_unregister_driver(&wl1271_sdio_driver); | ||
| 515 | } | ||
| 516 | module_exit(wl1271_exit); | ||
| 517 | |||
| 518 | MODULE_LICENSE("GPL"); | ||
| 519 | MODULE_AUTHOR("Roger Quadros <roger.quadros@nokia.com>"); | ||
| 520 | |||
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index d332b3f6d0fa..b44c75cd8c1e 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c | |||
| @@ -125,7 +125,6 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | |||
| 125 | /* queue (we use same identifiers for tid's and ac's */ | 125 | /* queue (we use same identifiers for tid's and ac's */ |
| 126 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 126 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
| 127 | desc->tid = ac; | 127 | desc->tid = ac; |
| 128 | |||
| 129 | desc->aid = TX_HW_DEFAULT_AID; | 128 | desc->aid = TX_HW_DEFAULT_AID; |
| 130 | desc->reserved = 0; | 129 | desc->reserved = 0; |
| 131 | 130 | ||
| @@ -228,7 +227,7 @@ static void handle_tx_low_watermark(struct wl1271 *wl) | |||
| 228 | unsigned long flags; | 227 | unsigned long flags; |
| 229 | 228 | ||
| 230 | if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && | 229 | if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && |
| 231 | skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { | 230 | wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) { |
| 232 | /* firmware buffer has space, restart queues */ | 231 | /* firmware buffer has space, restart queues */ |
| 233 | spin_lock_irqsave(&wl->wl_lock, flags); | 232 | spin_lock_irqsave(&wl->wl_lock, flags); |
| 234 | ieee80211_wake_queues(wl->hw); | 233 | ieee80211_wake_queues(wl->hw); |
| @@ -237,6 +236,43 @@ static void handle_tx_low_watermark(struct wl1271 *wl) | |||
| 237 | } | 236 | } |
| 238 | } | 237 | } |
| 239 | 238 | ||
| 239 | static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | ||
| 240 | { | ||
| 241 | struct sk_buff *skb = NULL; | ||
| 242 | unsigned long flags; | ||
| 243 | |||
| 244 | skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); | ||
| 245 | if (skb) | ||
| 246 | goto out; | ||
| 247 | skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); | ||
| 248 | if (skb) | ||
| 249 | goto out; | ||
| 250 | skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]); | ||
| 251 | if (skb) | ||
| 252 | goto out; | ||
| 253 | skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]); | ||
| 254 | |||
| 255 | out: | ||
| 256 | if (skb) { | ||
| 257 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
| 258 | wl->tx_queue_count--; | ||
| 259 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
| 260 | } | ||
| 261 | |||
| 262 | return skb; | ||
| 263 | } | ||
| 264 | |||
| 265 | static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) | ||
| 266 | { | ||
| 267 | unsigned long flags; | ||
| 268 | int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | ||
| 269 | |||
| 270 | skb_queue_head(&wl->tx_queue[q], skb); | ||
| 271 | spin_lock_irqsave(&wl->wl_lock, flags); | ||
| 272 | wl->tx_queue_count++; | ||
| 273 | spin_unlock_irqrestore(&wl->wl_lock, flags); | ||
| 274 | } | ||
| 275 | |||
| 240 | void wl1271_tx_work_locked(struct wl1271 *wl) | 276 | void wl1271_tx_work_locked(struct wl1271 *wl) |
| 241 | { | 277 | { |
| 242 | struct sk_buff *skb; | 278 | struct sk_buff *skb; |
| @@ -270,7 +306,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) | |||
| 270 | wl1271_acx_rate_policies(wl); | 306 | wl1271_acx_rate_policies(wl); |
| 271 | } | 307 | } |
| 272 | 308 | ||
| 273 | while ((skb = skb_dequeue(&wl->tx_queue))) { | 309 | while ((skb = wl1271_skb_dequeue(wl))) { |
| 274 | if (!woken_up) { | 310 | if (!woken_up) { |
| 275 | ret = wl1271_ps_elp_wakeup(wl, false); | 311 | ret = wl1271_ps_elp_wakeup(wl, false); |
| 276 | if (ret < 0) | 312 | if (ret < 0) |
| @@ -284,9 +320,9 @@ void wl1271_tx_work_locked(struct wl1271 *wl) | |||
| 284 | * Aggregation buffer is full. | 320 | * Aggregation buffer is full. |
| 285 | * Flush buffer and try again. | 321 | * Flush buffer and try again. |
| 286 | */ | 322 | */ |
| 287 | skb_queue_head(&wl->tx_queue, skb); | 323 | wl1271_skb_queue_head(wl, skb); |
| 288 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, | 324 | wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, |
| 289 | buf_offset, true); | 325 | buf_offset, true); |
| 290 | sent_packets = true; | 326 | sent_packets = true; |
| 291 | buf_offset = 0; | 327 | buf_offset = 0; |
| 292 | continue; | 328 | continue; |
| @@ -295,7 +331,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) | |||
| 295 | * Firmware buffer is full. | 331 | * Firmware buffer is full. |
| 296 | * Queue back last skb, and stop aggregating. | 332 | * Queue back last skb, and stop aggregating. |
| 297 | */ | 333 | */ |
| 298 | skb_queue_head(&wl->tx_queue, skb); | 334 | wl1271_skb_queue_head(wl, skb); |
| 299 | /* No work left, avoid scheduling redundant tx work */ | 335 | /* No work left, avoid scheduling redundant tx work */ |
| 300 | set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); | 336 | set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); |
| 301 | goto out_ack; | 337 | goto out_ack; |
| @@ -440,10 +476,13 @@ void wl1271_tx_reset(struct wl1271 *wl) | |||
| 440 | struct sk_buff *skb; | 476 | struct sk_buff *skb; |
| 441 | 477 | ||
| 442 | /* TX failure */ | 478 | /* TX failure */ |
| 443 | while ((skb = skb_dequeue(&wl->tx_queue))) { | 479 | for (i = 0; i < NUM_TX_QUEUES; i++) { |
| 444 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); | 480 | while ((skb = skb_dequeue(&wl->tx_queue[i]))) { |
| 445 | ieee80211_tx_status(wl->hw, skb); | 481 | wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); |
| 482 | ieee80211_tx_status(wl->hw, skb); | ||
| 483 | } | ||
| 446 | } | 484 | } |
| 485 | wl->tx_queue_count = 0; | ||
| 447 | 486 | ||
| 448 | /* | 487 | /* |
| 449 | * Make sure the driver is at a consistent state, in case this | 488 | * Make sure the driver is at a consistent state, in case this |
| @@ -472,8 +511,7 @@ void wl1271_tx_flush(struct wl1271 *wl) | |||
| 472 | mutex_lock(&wl->mutex); | 511 | mutex_lock(&wl->mutex); |
| 473 | wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", | 512 | wl1271_debug(DEBUG_TX, "flushing tx buffer: %d", |
| 474 | wl->tx_frames_cnt); | 513 | wl->tx_frames_cnt); |
| 475 | if ((wl->tx_frames_cnt == 0) && | 514 | if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { |
| 476 | skb_queue_empty(&wl->tx_queue)) { | ||
| 477 | mutex_unlock(&wl->mutex); | 515 | mutex_unlock(&wl->mutex); |
| 478 | return; | 516 | return; |
| 479 | } | 517 | } |
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 3c836e6063e6..ce3d31f98c55 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h | |||
| @@ -60,31 +60,32 @@ enum { | |||
| 60 | DEBUG_ALL = ~0, | 60 | DEBUG_ALL = ~0, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | #define DEBUG_LEVEL (DEBUG_NONE) | 63 | extern u32 wl12xx_debug_level; |
| 64 | 64 | ||
| 65 | #define DEBUG_DUMP_LIMIT 1024 | 65 | #define DEBUG_DUMP_LIMIT 1024 |
| 66 | 66 | ||
| 67 | #define wl1271_error(fmt, arg...) \ | 67 | #define wl1271_error(fmt, arg...) \ |
| 68 | printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg) | 68 | pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg) |
| 69 | 69 | ||
| 70 | #define wl1271_warning(fmt, arg...) \ | 70 | #define wl1271_warning(fmt, arg...) \ |
| 71 | printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg) | 71 | pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg) |
| 72 | 72 | ||
| 73 | #define wl1271_notice(fmt, arg...) \ | 73 | #define wl1271_notice(fmt, arg...) \ |
| 74 | printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg) | 74 | pr_info(DRIVER_PREFIX fmt "\n", ##arg) |
| 75 | 75 | ||
| 76 | #define wl1271_info(fmt, arg...) \ | 76 | #define wl1271_info(fmt, arg...) \ |
| 77 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg) | 77 | pr_info(DRIVER_PREFIX fmt "\n", ##arg) |
| 78 | 78 | ||
| 79 | #define wl1271_debug(level, fmt, arg...) \ | 79 | #define wl1271_debug(level, fmt, arg...) \ |
| 80 | do { \ | 80 | do { \ |
| 81 | if (level & DEBUG_LEVEL) \ | 81 | if (level & wl12xx_debug_level) \ |
| 82 | printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \ | 82 | pr_debug(DRIVER_PREFIX fmt "\n", ##arg); \ |
| 83 | } while (0) | 83 | } while (0) |
| 84 | 84 | ||
| 85 | /* TODO: use pr_debug_hex_dump when it will be available */ | ||
| 85 | #define wl1271_dump(level, prefix, buf, len) \ | 86 | #define wl1271_dump(level, prefix, buf, len) \ |
| 86 | do { \ | 87 | do { \ |
| 87 | if (level & DEBUG_LEVEL) \ | 88 | if (level & wl12xx_debug_level) \ |
| 88 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | 89 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ |
| 89 | DUMP_PREFIX_OFFSET, 16, 1, \ | 90 | DUMP_PREFIX_OFFSET, 16, 1, \ |
| 90 | buf, \ | 91 | buf, \ |
| @@ -94,7 +95,7 @@ enum { | |||
| 94 | 95 | ||
| 95 | #define wl1271_dump_ascii(level, prefix, buf, len) \ | 96 | #define wl1271_dump_ascii(level, prefix, buf, len) \ |
| 96 | do { \ | 97 | do { \ |
| 97 | if (level & DEBUG_LEVEL) \ | 98 | if (level & wl12xx_debug_level) \ |
| 98 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ | 99 | print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \ |
| 99 | DUMP_PREFIX_OFFSET, 16, 1, \ | 100 | DUMP_PREFIX_OFFSET, 16, 1, \ |
| 100 | buf, \ | 101 | buf, \ |
| @@ -174,108 +175,6 @@ struct wl1271_stats { | |||
| 174 | unsigned int excessive_retries; | 175 | unsigned int excessive_retries; |
| 175 | }; | 176 | }; |
| 176 | 177 | ||
| 177 | struct wl1271_debugfs { | ||
| 178 | struct dentry *rootdir; | ||
| 179 | struct dentry *fw_statistics; | ||
| 180 | |||
| 181 | struct dentry *tx_internal_desc_overflow; | ||
| 182 | |||
| 183 | struct dentry *rx_out_of_mem; | ||
| 184 | struct dentry *rx_hdr_overflow; | ||
| 185 | struct dentry *rx_hw_stuck; | ||
| 186 | struct dentry *rx_dropped; | ||
| 187 | struct dentry *rx_fcs_err; | ||
| 188 | struct dentry *rx_xfr_hint_trig; | ||
| 189 | struct dentry *rx_path_reset; | ||
| 190 | struct dentry *rx_reset_counter; | ||
| 191 | |||
| 192 | struct dentry *dma_rx_requested; | ||
| 193 | struct dentry *dma_rx_errors; | ||
| 194 | struct dentry *dma_tx_requested; | ||
| 195 | struct dentry *dma_tx_errors; | ||
| 196 | |||
| 197 | struct dentry *isr_cmd_cmplt; | ||
| 198 | struct dentry *isr_fiqs; | ||
| 199 | struct dentry *isr_rx_headers; | ||
| 200 | struct dentry *isr_rx_mem_overflow; | ||
| 201 | struct dentry *isr_rx_rdys; | ||
| 202 | struct dentry *isr_irqs; | ||
| 203 | struct dentry *isr_tx_procs; | ||
| 204 | struct dentry *isr_decrypt_done; | ||
| 205 | struct dentry *isr_dma0_done; | ||
| 206 | struct dentry *isr_dma1_done; | ||
| 207 | struct dentry *isr_tx_exch_complete; | ||
| 208 | struct dentry *isr_commands; | ||
| 209 | struct dentry *isr_rx_procs; | ||
| 210 | struct dentry *isr_hw_pm_mode_changes; | ||
| 211 | struct dentry *isr_host_acknowledges; | ||
| 212 | struct dentry *isr_pci_pm; | ||
| 213 | struct dentry *isr_wakeups; | ||
| 214 | struct dentry *isr_low_rssi; | ||
| 215 | |||
| 216 | struct dentry *wep_addr_key_count; | ||
| 217 | struct dentry *wep_default_key_count; | ||
| 218 | /* skipping wep.reserved */ | ||
| 219 | struct dentry *wep_key_not_found; | ||
| 220 | struct dentry *wep_decrypt_fail; | ||
| 221 | struct dentry *wep_packets; | ||
| 222 | struct dentry *wep_interrupt; | ||
| 223 | |||
| 224 | struct dentry *pwr_ps_enter; | ||
| 225 | struct dentry *pwr_elp_enter; | ||
| 226 | struct dentry *pwr_missing_bcns; | ||
| 227 | struct dentry *pwr_wake_on_host; | ||
| 228 | struct dentry *pwr_wake_on_timer_exp; | ||
| 229 | struct dentry *pwr_tx_with_ps; | ||
| 230 | struct dentry *pwr_tx_without_ps; | ||
| 231 | struct dentry *pwr_rcvd_beacons; | ||
| 232 | struct dentry *pwr_power_save_off; | ||
| 233 | struct dentry *pwr_enable_ps; | ||
| 234 | struct dentry *pwr_disable_ps; | ||
| 235 | struct dentry *pwr_fix_tsf_ps; | ||
| 236 | /* skipping cont_miss_bcns_spread for now */ | ||
| 237 | struct dentry *pwr_rcvd_awake_beacons; | ||
| 238 | |||
| 239 | struct dentry *mic_rx_pkts; | ||
| 240 | struct dentry *mic_calc_failure; | ||
| 241 | |||
| 242 | struct dentry *aes_encrypt_fail; | ||
| 243 | struct dentry *aes_decrypt_fail; | ||
| 244 | struct dentry *aes_encrypt_packets; | ||
| 245 | struct dentry *aes_decrypt_packets; | ||
| 246 | struct dentry *aes_encrypt_interrupt; | ||
| 247 | struct dentry *aes_decrypt_interrupt; | ||
| 248 | |||
| 249 | struct dentry *event_heart_beat; | ||
| 250 | struct dentry *event_calibration; | ||
| 251 | struct dentry *event_rx_mismatch; | ||
| 252 | struct dentry *event_rx_mem_empty; | ||
| 253 | struct dentry *event_rx_pool; | ||
| 254 | struct dentry *event_oom_late; | ||
| 255 | struct dentry *event_phy_transmit_error; | ||
| 256 | struct dentry *event_tx_stuck; | ||
| 257 | |||
| 258 | struct dentry *ps_pspoll_timeouts; | ||
| 259 | struct dentry *ps_upsd_timeouts; | ||
| 260 | struct dentry *ps_upsd_max_sptime; | ||
| 261 | struct dentry *ps_upsd_max_apturn; | ||
| 262 | struct dentry *ps_pspoll_max_apturn; | ||
| 263 | struct dentry *ps_pspoll_utilization; | ||
| 264 | struct dentry *ps_upsd_utilization; | ||
| 265 | |||
| 266 | struct dentry *rxpipe_rx_prep_beacon_drop; | ||
| 267 | struct dentry *rxpipe_descr_host_int_trig_rx_data; | ||
| 268 | struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data; | ||
| 269 | struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data; | ||
| 270 | struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data; | ||
| 271 | |||
| 272 | struct dentry *tx_queue_len; | ||
| 273 | |||
| 274 | struct dentry *retry_count; | ||
| 275 | struct dentry *excessive_retries; | ||
| 276 | struct dentry *gpio_power; | ||
| 277 | }; | ||
| 278 | |||
| 279 | #define NUM_TX_QUEUES 4 | 178 | #define NUM_TX_QUEUES 4 |
| 280 | #define NUM_RX_PKT_DESC 8 | 179 | #define NUM_RX_PKT_DESC 8 |
| 281 | 180 | ||
| @@ -393,7 +292,8 @@ struct wl1271 { | |||
| 393 | int session_counter; | 292 | int session_counter; |
| 394 | 293 | ||
| 395 | /* Frames scheduled for transmission, not handled yet */ | 294 | /* Frames scheduled for transmission, not handled yet */ |
| 396 | struct sk_buff_head tx_queue; | 295 | struct sk_buff_head tx_queue[NUM_TX_QUEUES]; |
| 296 | int tx_queue_count; | ||
| 397 | 297 | ||
| 398 | struct work_struct tx_work; | 298 | struct work_struct tx_work; |
| 399 | 299 | ||
| @@ -431,6 +331,9 @@ struct wl1271 { | |||
| 431 | struct wl1271_scan scan; | 331 | struct wl1271_scan scan; |
| 432 | struct delayed_work scan_complete_work; | 332 | struct delayed_work scan_complete_work; |
| 433 | 333 | ||
| 334 | /* probe-req template for the current AP */ | ||
| 335 | struct sk_buff *probereq; | ||
| 336 | |||
| 434 | /* Our association ID */ | 337 | /* Our association ID */ |
| 435 | u16 aid; | 338 | u16 aid; |
| 436 | 339 | ||
| @@ -475,7 +378,7 @@ struct wl1271 { | |||
| 475 | int last_rssi_event; | 378 | int last_rssi_event; |
| 476 | 379 | ||
| 477 | struct wl1271_stats stats; | 380 | struct wl1271_stats stats; |
| 478 | struct wl1271_debugfs debugfs; | 381 | struct dentry *rootdir; |
| 479 | 382 | ||
| 480 | __le32 buffer_32; | 383 | __le32 buffer_32; |
| 481 | u32 buffer_cmd; | 384 | u32 buffer_cmd; |
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index 184628027213..be21032f4dc1 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __WL12XX_80211_H__ | 2 | #define __WL12XX_80211_H__ |
| 3 | 3 | ||
| 4 | #include <linux/if_ether.h> /* ETH_ALEN */ | 4 | #include <linux/if_ether.h> /* ETH_ALEN */ |
| 5 | #include <linux/if_arp.h> | ||
| 5 | 6 | ||
| 6 | /* RATES */ | 7 | /* RATES */ |
| 7 | #define IEEE80211_CCK_RATE_1MB 0x02 | 8 | #define IEEE80211_CCK_RATE_1MB 0x02 |
| @@ -133,11 +134,17 @@ struct wl12xx_qos_null_data_template { | |||
| 133 | __le16 qos_ctl; | 134 | __le16 qos_ctl; |
| 134 | } __packed; | 135 | } __packed; |
| 135 | 136 | ||
| 136 | struct wl12xx_probe_req_template { | 137 | struct wl12xx_arp_rsp_template { |
| 137 | struct ieee80211_header header; | 138 | struct ieee80211_hdr_3addr hdr; |
| 138 | struct wl12xx_ie_ssid ssid; | 139 | |
| 139 | struct wl12xx_ie_rates rates; | 140 | u8 llc_hdr[sizeof(rfc1042_header)]; |
| 140 | struct wl12xx_ie_rates ext_rates; | 141 | u16 llc_type; |
| 142 | |||
| 143 | struct arphdr arp_hdr; | ||
| 144 | u8 sender_hw[ETH_ALEN]; | ||
| 145 | u32 sender_ip; | ||
| 146 | u8 target_hw[ETH_ALEN]; | ||
| 147 | u32 target_ip; | ||
| 141 | } __packed; | 148 | } __packed; |
| 142 | 149 | ||
| 143 | 150 | ||
