From patchwork Wed Jan 4 17:58:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?UmFmYcWCIE1pxYJlY2tp?= X-Patchwork-Id: 9497121 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 290B3606B5 for ; Wed, 4 Jan 2017 18:03:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D4EE280DE for ; Wed, 4 Jan 2017 18:03:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 121AC2818B; Wed, 4 Jan 2017 18:03:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 370C4280DE for ; Wed, 4 Jan 2017 18:03:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934986AbdADSAb (ORCPT ); Wed, 4 Jan 2017 13:00:31 -0500 Received: from mail-lf0-f65.google.com ([209.85.215.65]:34643 "EHLO mail-lf0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752087AbdADR7g (ORCPT ); Wed, 4 Jan 2017 12:59:36 -0500 Received: by mail-lf0-f65.google.com with SMTP id d16so33312281lfb.1; Wed, 04 Jan 2017 09:58:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BRnHatZ69F7DsrWS1l1QT/IJUnmDVFqFfe3aM4V/39k=; b=M3daKLVyHAzTP5i74Xc7Vqpgu2FNBa2Fz1184MRzryI1ddET6pt9Khy5gL5IuYieXD wxKZUXd0eTi35WFyoVHQC1IPWgM7gsh3zFnJqn+0Ert5DaTqHNvvuh8Qz8uYE4wZhVKw LChZNQRYphTiX9dUyzz1uKhepfUn5DKE0ADs1T82U7I7lH8XvFVR6TgbCnPodT7dXvmG JAIsdgFTdWq/kktEC8ok54OZ2vXfdFMswmDANw2rhXXkyg9A1kxekBwv3yNf12fEyrAQ SQHJImqoIfAB++UuzYCLsGzH8R3ys2/MBaTvqV5UD1DehktSjAQZt2cJHOj8kA+uKf8x s7pw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BRnHatZ69F7DsrWS1l1QT/IJUnmDVFqFfe3aM4V/39k=; b=pCZNvMCZTvhId8lp2srB3lY8WnH6gm/LQfAOhw+b0SCMd/K3RTQ+KGf35+WvC5Pfup cDFG0Qc24v7MD1OZLCJI8odjPoGbmFdv7qmZ8w+QS1+kqVagNzESv7B8fPXjAaChXo7V sIwK8k7WoZgnKWFk9RI8Y5Cbr1YYWJzBtW4xFP+b/s2fsrVWlXk7iZ7QtGmTzfPFSI7T P4w577q3sCh+8pCKtx4qTsr8oxdOxpeI/RpT1W06xMW0dQDO5P1WZSiYK22U0smw8HQk ERsoSpOBkAPIbjKKB3gI7pwnuT7bXH0ap604naBCneLwGCTdAF1RLd80pYJocSUqboIl fZJQ== X-Gm-Message-State: AIkVDXIkzlbbdlIJMUDOv1X5ElcEVTNvJlwgWBEb+KA3mlZoPubKNgtvqNthqCZ6SE9CKQ== X-Received: by 10.25.212.82 with SMTP id l79mr18960500lfg.155.1483552725811; Wed, 04 Jan 2017 09:58:45 -0800 (PST) Received: from linux-samsung.lan (ip-194-187-74-233.konfederacka.maverick.com.pl. [194.187.74.233]) by smtp.gmail.com with ESMTPSA id c78sm17694967lfc.39.2017.01.04.09.58.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Jan 2017 09:58:45 -0800 (PST) From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= To: Johannes Berg , linux-wireless@vger.kernel.org Cc: Martin Blumenstingl , Felix Fietkau , Arend van Spriel , Arnd Bergmann , devicetree@vger.kernel.org, Rob Herring , =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Subject: [PATCH V6 3/3] cfg80211: support ieee80211-freq-limit DT property Date: Wed, 4 Jan 2017 18:58:31 +0100 Message-Id: <20170104175832.25996-3-zajec5@gmail.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20170104175832.25996-1-zajec5@gmail.com> References: <20170104175832.25996-1-zajec5@gmail.com> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rafał Miłecki This patch adds a helper for reading that new property and applying limitations of supported channels specified this way. It is used with devices that normally support a wide wireless band but in a given config are limited to some part of it (usually due to board design). For example a dual-band chipset may be able to support one band only because of used antennas. It's also common that tri-band routers have separated radios for lower and higher part of 5 GHz band and it may be impossible to say which is which without a DT info. Signed-off-by: Rafał Miłecki --- V2: Put main code in core.c as it isn't strictly part of regulatory - pointed by Arend. Update to support ieee80211-freq-limit (new property). V3: Introduce separated wiphy_read_of_freq_limits function. Add extra sanity checks for DT data. Move code back to reg.c as suggested by Johannes. V4: Move code to of.c Use one helper called at init time (no runtime hooks) Modify orig_flags V5: Make wiphy_read_of_freq_limits return void as there isn't much point of handling errors. V6: Set IEEE80211_CHAN_DISABLED in "flags" instead of "orig_flags" as they will be copied during wiphy_register. Also improve description & note that helper has to be called before wiphy_register. --- include/net/cfg80211.h | 28 ++++++++++ net/wireless/Makefile | 1 + net/wireless/of.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 net/wireless/of.c diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ca2ac1c..30841a9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -311,6 +311,34 @@ struct ieee80211_supported_band { struct ieee80211_sta_vht_cap vht_cap; }; +/** + * wiphy_read_of_freq_limits - read frequency limits from device tree + * + * @wiphy: the wireless device to get extra limits for + * + * Some devices may have extra limitations specified in DT. This may be useful + * for chipsets that normally support more bands but are limited due to board + * design (e.g. by antennas or external power amplifier). + * + * This function reads info from DT and uses it to *modify* channels (disable + * unavailable ones). It's usually a *bad* idea to use it in drivers with + * shared channel data as DT limitations are device specific. You should make + * sure to call it only if channels in wiphy are copied and can be modified + * without affecting other devices. + * + * As this function access device node it has to be called after set_wiphy_dev. + * It also modifies channels so they have to be set first. + * If using this helper, call it before wiphy_register. + */ +#ifdef CONFIG_OF +void wiphy_read_of_freq_limits(struct wiphy *wiphy); +#else /* CONFIG_OF */ +static inline void wiphy_read_of_freq_limits(struct wiphy *wiphy) +{ +} +#endif /* !CONFIG_OF */ + + /* * Wireless hardware/device configuration structures and methods */ diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 4c9e39f..95b4c09 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o +cfg80211-$(CONFIG_OF) += of.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o diff --git a/net/wireless/of.c b/net/wireless/of.c new file mode 100644 index 0000000..de221f0 --- /dev/null +++ b/net/wireless/of.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2017 Rafał Miłecki + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "core.h" + +static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy, + struct ieee80211_freq_range *freq_limits, + unsigned int n_freq_limits, + struct ieee80211_channel *chan) +{ + u32 bw = MHZ_TO_KHZ(20); + int i; + + for (i = 0; i < n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &freq_limits[i]; + + if (cfg80211_does_bw_fit_range(limit, + MHZ_TO_KHZ(chan->center_freq), + bw)) + return true; + } + + return false; +} + +static void wiphy_freq_limits_apply(struct wiphy *wiphy, + struct ieee80211_freq_range *freq_limits, + unsigned int n_freq_limits) +{ + enum nl80211_band band; + int i; + + if (WARN_ON(!n_freq_limits)) + return; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + struct ieee80211_supported_band *sband = wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!wiphy_freq_limits_valid_chan(wiphy, freq_limits, + n_freq_limits, + chan)) { + pr_debug("Disabling freq %d MHz as it's out of OF limits\n", + chan->center_freq); + chan->flags |= IEEE80211_CHAN_DISABLED; + } + } + } +} + +void wiphy_read_of_freq_limits(struct wiphy *wiphy) +{ + struct device *dev = wiphy_dev(wiphy); + struct device_node *np; + struct property *prop; + struct ieee80211_freq_range *freq_limits; + unsigned int n_freq_limits; + const __be32 *p; + int len, i; + int err = 0; + + if (!dev) + return; + np = dev_of_node(dev); + if (!np) + return; + + prop = of_find_property(np, "ieee80211-freq-limit", &len); + if (!prop) + return; + + if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) { + dev_err(dev, "ieee80211-freq-limit wrong format"); + return; + } + n_freq_limits = len / sizeof(u32) / 2; + + freq_limits = kcalloc(n_freq_limits, sizeof(*freq_limits), GFP_KERNEL); + if (!freq_limits) { + err = -ENOMEM; + goto out_kfree; + } + + p = NULL; + for (i = 0; i < n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &freq_limits[i]; + + p = of_prop_next_u32(prop, p, &limit->start_freq_khz); + if (!p) { + err = -EINVAL; + goto out_kfree; + } + + p = of_prop_next_u32(prop, p, &limit->end_freq_khz); + if (!p) { + err = -EINVAL; + goto out_kfree; + } + + if (!limit->start_freq_khz || + !limit->end_freq_khz || + limit->start_freq_khz >= limit->end_freq_khz) { + err = -EINVAL; + goto out_kfree; + } + } + + wiphy_freq_limits_apply(wiphy, freq_limits, n_freq_limits); + +out_kfree: + kfree(freq_limits); + if (err) + dev_err(dev, "Failed to get limits: %d\n", err); +} +EXPORT_SYMBOL(wiphy_read_of_freq_limits);