From patchwork Tue Jun 16 21:16:46 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Rompf X-Patchwork-Id: 485184 X-Patchwork-Delegate: nbd@openwrt.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from arrakis.dune.hu (arrakis.dune.hu [78.24.191.176]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A909D1402AA for ; Wed, 17 Jun 2015 07:23:08 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=loplof.de header.i=@loplof.de header.b=MkgMMk+9; dkim-atps=neutral Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 6C3BD28BF50; Tue, 16 Jun 2015 23:21:34 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on arrakis.dune.hu X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 25F0128BF16 for ; Tue, 16 Jun 2015 23:21:17 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 CL_IP_EQ_HELO_IP=-2 (check from: .loplof. - helo: .mo4-p00-ob.smtp.rzone. - helo-domain: .rzone.) FROM/MX_MATCHES_HELO(DOMAIN)=-2; rate: -8.5 Received: from mo4-p00-ob.smtp.rzone.de (mo4-p00-ob.smtp.rzone.de [81.169.146.218]) by arrakis.dune.hu (Postfix) with ESMTPS for ; Tue, 16 Jun 2015 23:21:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1434489679; l=13988; s=domk; d=loplof.de; h=Content-Transfer-Encoding:Content-Type:MIME-Version:In-Reply-To: References:Cc:Date:Subject:To:From; bh=+aogUI6O/EpDEnyrcPBDjrQwZtI3Jq+AYpufeDBZ9Yw=; b=MkgMMk+9ouOYuC5QVD9+pa3kvd30Q8sKk1BVo2ogV4xfO0c3+A2IQhip/U57mhDSLFU KN6ieGjCmnFu7UkyjF0GuJRGw6l2BjwFH20ni9cjBXZTsLtVbO6m7CUVKAhkRZHHfEyDG WteDIzk8E8vpGAKYGQg5I1h8/DStoMBlW+A= X-RZG-AUTH: :P3gBc0GmW/MnlBFpG8pTynGixNLZJ3Qpuna7EXLmjrAdigkJRo+wFNteWA== X-RZG-CLASS-ID: mo00 Received: from dose.localnet (x55b4de84.dyn.telefonica.de [85.180.222.132]) by smtp.strato.de (RZmta 37.7 DYNA|AUTH) with ESMTPA id z023e6r5GLLHiyf; Tue, 16 Jun 2015 23:21:17 +0200 (CEST) From: Stefan Rompf To: Felix Fietkau Date: Tue, 16 Jun 2015 23:16:46 +0200 User-Agent: KMail/1.13.6 (Linux/3.16.7-7-desktop; KDE/4.14.6; x86_64; ; ) References: <201506162314.05550.stefan@loplof.de> In-Reply-To: <201506162314.05550.stefan@loplof.de> MIME-Version: 1.0 Message-Id: <201506162316.46858.stefan@loplof.de> Cc: openwrt-devel@lists.openwrt.org Subject: Re: [OpenWrt-Devel] [PATCH v4 2/2] Add HSR tuner to ath9k X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openwrt-devel-bounces@lists.openwrt.org Sender: "openwrt-devel" Add tuner for the HSR filter of the UniFi Outdoor Plus access point. Usage of the tuner is controlled at runtime by ath9k_platform_data. The code can be enabled or disabled by a compile time option. Signed-off-by: Stefan Rompf Index: package/kernel/mac80211/Makefile =================================================================== --- package/kernel/mac80211/Makefile (Revision 46000) +++ package/kernel/mac80211/Makefile (Arbeitskopie) @@ -587,6 +587,11 @@ bool "Support chips used in PC OEM cards" depends on PACKAGE_kmod-ath9k + config ATH9K_UBNTHSR + bool "Support for Ubiquiti UniFi Outdoor Plus access point" + depends on PACKAGE_kmod-ath9k + default y + endef define KernelPackage/ath9k-htc @@ -1558,6 +1563,7 @@ config-$(CONFIG_PCI) += ATH9K_PCI config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM +config-$(CONFIG_ATH9K_UBNTHSR) += ATH9K_UBNTHSR config-$(call config_package,ath9k-htc) += ATH9K_HTC config-$(call config_package,ath10k) += ATH10K ATH10K_PCI Index: package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch =================================================================== --- package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch (Revision 0) +++ package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch (Arbeitskopie) @@ -0,0 +1,373 @@ +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/channel.c 2015-06-16 09:28:34.000000000 +0200 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/channel.c 2015-06-16 09:49:53.000000000 +0200 +@@ -15,6 +15,8 @@ + */ + + #include "ath9k.h" ++#include ++#include "hsr.h" + + /* Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending +@@ -22,6 +24,7 @@ + */ + static int ath_set_channel(struct ath_softc *sc) + { ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hw *hw = sc->hw; +@@ -41,6 +44,11 @@ + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + chan->center_freq, chandef->width); + ++ if (pdata && pdata->ubnt_hsr) { ++ hsr_enable(ah, chandef->width, chan->center_freq); ++ hsr_status(ah); ++ } ++ + /* update survey stats for the old channel before switching */ + spin_lock_bh(&common->cc_lock); + ath_update_survey_stats(sc); +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/hsr.c 1970-01-01 01:00:00.000000000 +0100 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/hsr.c 2015-06-16 09:41:24.000000000 +0200 +@@ -0,0 +1,220 @@ ++/* ++ * ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hw.h" ++#include "ath9k.h" ++ ++#define HSR_GPIO_CSN 8 ++#define HSR_GPIO_CLK 6 ++#define HSR_GPIO_DOUT 7 ++#define HSR_GPIO_DIN 5 ++ ++/* delays are in useconds */ ++#define HSR_DELAY_HALF_TICK 100 ++#define HSR_DELAY_PRE_WRITE 75 ++#define HSR_DELAY_FINAL 20000 ++#define HSR_DELAY_TRAILING 200 ++ ++ ++void hsr_init(struct ath_hw* ah) { ++ ath9k_hw_cfg_gpio_input(ah, HSR_GPIO_DIN); ++ ath9k_hw_cfg_output(ah, HSR_GPIO_CSN, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_cfg_output(ah, HSR_GPIO_CLK, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ath9k_hw_cfg_output(ah, HSR_GPIO_DOUT, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0); ++ ++ udelay(HSR_DELAY_TRAILING); ++} ++ ++static u32 hsr_write_byte(struct ath_hw* ah, int delay, u32 value){ ++ struct ath_common *common = ath9k_hw_common(ah); ++ int i; ++ u32 rval = 0; ++ ++ udelay(delay); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ for( i = 0; i < 8; ++i) { ++ rval = rval << 1; ++ ++ // pattern is left to right, that is 7-th bit runs first ++ ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN); ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0); ++ udelay(HSR_DELAY_HALF_TICK); ++ } ++ ++ ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1); ++ udelay(HSR_DELAY_HALF_TICK); ++ ++ ath_dbg(common, CONFIG, "hsr_write_byte: write byte %d return value is %d %c\n", ++ value, rval, rval > 32 ? rval : '-'); ++ ++ return rval & 0xff; ++} ++ ++static int hsr_write_a_chain(struct ath_hw* ah, char* chain, int items) { ++ int i = 0; ++ int status = 0; ++ ++ // a preamble ++ hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ ++ // clear HSR's reply buffer ++ if (status) { ++ int loop = 0; ++ for ( loop = 0; (loop < 42) && status; ++loop) { ++ status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ } ++ if ( loop >= 42) { ++ ATH_DBG_WARN("hsr_write_a_chain: can't clear an output buffer after a 42 cycles.\n"); ++ return -1; ++ } ++ } ++ ++ for ( i =0; (i < items) && ( 0 != chain[i]); ++i) { ++ hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]); ++ } ++ ++ hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ mdelay(HSR_DELAY_FINAL / 1000); ++ ++ // reply ++ memset(chain, 0, items); ++ ++ hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0); ++ udelay(HSR_DELAY_TRAILING); ++ ++ for ( i = 0; i < (items - 1); ++i) { ++ u32 ret; ++ if ( 0 != (ret = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0))) { ++ chain[i] = (char)ret; ++ } else { ++ break; ++ } ++ udelay(HSR_DELAY_TRAILING); ++ } ++ ++ return (1 < i) ? simple_strtol(chain + 1, NULL, 10) : 0; ++} ++ ++int hsr_disable(struct ath_hw* ah) { ++ char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0}; ++ int ret; ++ ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( (ret > 0) && (*cmd == 'B')) { ++ return 0; ++ } ++ ++ return -1; ++} ++ ++int hsr_enable(struct ath_hw* ah, int bw, int fq) { ++ char cmd[10]; ++ int ret; ++ ++ /* Bandwidth argument is 0 sometimes. Assume default 802.11bgn ++ 20MHz on invalid values */ ++ if ( (bw != 5) && (bw != 10) && (bw != 20) && (bw != 40)) { ++ bw = 20; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'b'; // 98 ++ snprintf(cmd + 1, 3, "%02d", bw); ++ ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( (*cmd != 'B') || (ret != bw)) { ++ ATH_DBG_WARN("hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d) \n", 'b', bw, *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'x'; // 120 ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( *cmd != 'X') { ++ ATH_DBG_WARN("hsr_enable: failed 'x' command -> reply (%d, %d) \n", *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'm'; // 109 ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( *cmd != 'M') { ++ ATH_DBG_WARN("hsr_enable: failed 'm' command -> reply (%d, %d) \n", *cmd, ret); ++ return -1; ++ } ++ ++ memset(cmd, 0, sizeof(cmd)); ++ *cmd = 'f'; // 102 ++ snprintf(cmd + 1, 6, "%05d", fq); ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( (*cmd != 'F') && (ret != fq)) { ++ ATH_DBG_WARN("hsr_enable: failed set frequency -> reply (%d, %d) \n", *cmd, ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int hsr_status(struct ath_hw* ah) { ++ char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 115 ++ int ret; ++ ++ ret = hsr_write_a_chain(ah, cmd, sizeof(cmd)); ++ if ( (*cmd != 'S')) { ++ ATH_DBG_WARN("hsr_status: returned %d,%d \n", *cmd, ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/hsr.h 1970-01-01 01:00:00.000000000 +0100 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/hsr.h 2015-06-16 09:17:52.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* ++ * The MIT License (MIT) ++ * ++ * Copyright (c) 2015 Kirill Berezin ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in all ++ * copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef HSR_H_ ++#define HSR_H_ ++ ++#ifdef CPTCFG_ATH9K_UBNTHSR ++void hsr_init(struct ath_hw* ah); ++int hsr_disable(struct ath_hw* ah); ++int hsr_enable(struct ath_hw* ah, int bw, int fq); ++int hsr_status(struct ath_hw* ah); ++#else ++static inline void hsr_init(struct ath_hw* ah) {} ++static inline int hsr_disable(struct ath_hw* ah) { return 0; } ++static inline int hsr_enable(struct ath_hw* ah, int bw, int fq) { return 0; } ++static inline int hsr_status(struct ath_hw* ah) { return 0; } ++#endif ++ ++#endif /* HSR_H_ */ +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/Kconfig 2015-03-10 04:37:16.000000000 +0100 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/Kconfig 2015-06-16 09:13:53.000000000 +0200 +@@ -59,6 +59,20 @@ + Say Y, if you have a SoC with a compatible built-in + wireless MAC. Say N if unsure. + ++config ATH9K_UBNTHSR ++ bool "Ubiquiti UniFi Outdoor Plus HSR support" ++ depends on ATH9K ++ default y ++ ---help--- ++ This options enables code to control the HSR RF ++ filter in the receive path of the Ubiquiti UniFi ++ Outdoor Plus access point. ++ ++ Say Y, if you want to use the access point. The ++ code will only be used if the device is detected, ++ so it does not harm other setup other than occupying ++ a bit of memory. ++ + config ATH9K_DEBUGFS + bool "Atheros ath9k debugging" + depends on ATH9K && DEBUG_FS +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/main.c 2015-06-16 08:45:50.000000000 +0200 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/main.c 2015-06-16 09:49:43.000000000 +0200 +@@ -16,8 +16,10 @@ + + #include + #include ++#include + #include "ath9k.h" + #include "btcoex.h" ++#include "hsr.h" + + u8 ath9k_parse_mpdudensity(u8 mpdudensity) + { +@@ -652,6 +654,7 @@ + static int ath9k_start(struct ieee80211_hw *hw) + { + struct ath_softc *sc = hw->priv; ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; +@@ -730,6 +733,11 @@ + (ah->config.led_active_high) ? 1 : 0); + } + ++ if (pdata && pdata->ubnt_hsr) { ++ hsr_init(ah); ++ hsr_disable(ah); ++ } ++ + /* + * Reset key cache to sane defaults (all entries cleared) instead of + * semi-random values after suspend/resume. +--- compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k.orig/Makefile 2015-03-10 04:37:16.000000000 +0100 ++++ compat-wireless-2015-03-09/drivers/net/wireless/ath/ath9k/Makefile 2015-06-16 09:14:59.000000000 +0200 +@@ -15,6 +15,7 @@ + ath9k-$(CPTCFG_ATH9K_DFS_CERTIFIED) += dfs.o + ath9k-$(CPTCFG_ATH9K_TX99) += tx99.o + ath9k-$(CPTCFG_ATH9K_WOW) += wow.o ++ath9k-$(CPTCFG_ATH9K_UBNTHSR) += hsr.o + + ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o + +--- compat-wireless-2015-03-09/.local-symbols.orig 2015-06-16 14:54:43.000000000 +0200 ++++ compat-wireless-2015-03-09/.local-symbols 2015-06-16 14:54:45.000000000 +0200 +@@ -115,6 +115,7 @@ + ATH9K_RFKILL= + ATH9K_CHANNEL_CONTEXT= + ATH9K_PCOEM= ++ATH9K_UBNTHSR= + ATH9K_HTC= + ATH9K_HTC_DEBUGFS= + CARL9170=