From patchwork Mon Jan 2 16:32:08 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: 9493851 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 73B7360414 for ; Mon, 2 Jan 2017 16:32:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 65099223B2 for ; Mon, 2 Jan 2017 16:32:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 589BB1FE7A; Mon, 2 Jan 2017 16:32:44 +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 AEF861FE7A for ; Mon, 2 Jan 2017 16:32:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933382AbdABQca (ORCPT ); Mon, 2 Jan 2017 11:32:30 -0500 Received: from mail-lf0-f67.google.com ([209.85.215.67]:35330 "EHLO mail-lf0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933373AbdABQc2 (ORCPT ); Mon, 2 Jan 2017 11:32:28 -0500 Received: by mail-lf0-f67.google.com with SMTP id x140so26125794lfa.2; Mon, 02 Jan 2017 08:32:27 -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=SjrtlBOLs1+ebT/lKvpq5RVYBw1hgKvMivLSzyoX2hA=; b=InNtV3N7H11P32ODq60f7bdFBwx2La/8MBiJfLkbHpXz6p/pm/NJx9ekCye0NvREay FHD7uXlNpasQGJzEQ9znTt5n28BfMdkIFSCsxZ7pAICV2z9rN0wQFEIvfnJMdUJnRnun HlcllvDn/PJ5++SZeXtaxo+q7UZNRl2oSCJPxctJZJU0dqB9ilbCBCzkUoh0Lp4VaBj0 1DP+4dhvP0gEHtEs/tYQY3mqd9KMaBGRGplx3Lc2ZAxqGVxfY7feVP5VUOnTVFcoVkAK deYmXjm7sRf6di70CytteBkob5Z20bsCrm8AhkqTOIgjJiLpFqIYbGXcRcjEslQcPSfC zz6Q== 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=SjrtlBOLs1+ebT/lKvpq5RVYBw1hgKvMivLSzyoX2hA=; b=NWHHFnGkyYIIvLFaUmnPOfHb+a4zzVQ206oCEohj/5wWaYnURCO6ZWfLxyLECRfCiQ FIArJcBfH+z98HRoiwoVZVq5lS6wDSP4lD5cIKMpYglenaoIUFbUoeGYJ1Rgv28RX+t/ 2mNxFnLOj/4Q3MxbddQkfP0Dwj6Q8wljHR8dRW+wCmPlehufOxreF19vNrn4l52OEsRm LxXKZO1jIkjOZmwjXMnn7qnavi1mvSnwOQ9ZpWj8GcVIMfJ7tlaijhiXTB/F7K9RLPGz HyaXSD3oCtjBVkMUmy4iECJjMyhg2UhrD0mxxIgNE0LNSxh9eyWO4LfiFbxlq6tn2Fa7 llww== X-Gm-Message-State: AIkVDXIh0ffHQojdEHY3lTlb1cKGCVrq3emY0KY+ezoZwmev0fWsYg7dxGPctpHumXIrPQ== X-Received: by 10.46.14.9 with SMTP id 9mr19178323ljo.59.1483374746529; Mon, 02 Jan 2017 08:32:26 -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 204sm16126252ljj.33.2017.01.02.08.32.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 02 Jan 2017 08:32:25 -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, =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Subject: [PATCH V3 2/2] cfg80211: support ieee80211-freq-limit DT property Date: Mon, 2 Jan 2017 17:32:08 +0100 Message-Id: <20170102163209.2445-2-zajec5@gmail.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20170102163209.2445-1-zajec5@gmail.com> References: <20170102163209.2445-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 It allows specifying hardware limitations of supported channels. This may be useful for specifying single band devices or devices that support only some part of the whole band. This can be useful for some tri-band routers that have separated radios for lower and higher part of 5 GHz band. 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. --- include/net/cfg80211.h | 23 ++++++++++ net/wireless/core.c | 1 + net/wireless/reg.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ca2ac1c..5002625 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3515,6 +3515,9 @@ struct wiphy_iftype_ext_capab { * attribute indices defined in &enum nl80211_bss_select_attr. * * @cookie_counter: unique generic cookie counter, used to identify objects. + * + * @n_freq_limits: number of frequency limits + * @freq_limits: array of extra frequency limits */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -3646,6 +3649,9 @@ struct wiphy { u64 cookie_counter; + unsigned int n_freq_limits; + struct ieee80211_freq_range *freq_limits; + char priv[0] __aligned(NETDEV_ALIGN); }; @@ -4278,6 +4284,23 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, */ /** + * 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 extermal power amplifier). + * + * This function reads info from DT and uses it to *modify* channels (disable + * unavailable ones) in a regulary code. It's usually a *bad* idea to use it in + * drivers with *shared* channel data as DT limitations are device specific. + * + * As this function access device node it has to be called after set_wiphy_dev. + */ +int wiphy_read_of_freq_limits(struct wiphy *wiphy); + +/** * regulatory_hint - driver hint to the wireless core a regulatory domain * @wiphy: the wireless device giving the hint (used only for reporting * conflicts) diff --git a/net/wireless/core.c b/net/wireless/core.c index 158c59e..c1b5fc7 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -940,6 +940,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) void wiphy_free(struct wiphy *wiphy) { + kfree(wiphy->freq_limits); put_device(&wiphy->dev); } EXPORT_SYMBOL(wiphy_free); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5dbac37..e00fd5b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1158,6 +1158,120 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd return bw_flags; } +int wiphy_read_of_freq_limits(struct wiphy *wiphy) +{ + struct device *dev = wiphy_dev(wiphy); + struct device_node *np; + struct property *prop; + const __be32 *p; + int len, i, err; + + if (wiphy->n_freq_limits) + return 0; + + if (!dev) + return 0; + np = dev_of_node(dev); + if (!np) + return 0; + + prop = of_find_property(np, "ieee80211-freq-limit", &len); + if (!prop) + return 0; + + if (!len || len % sizeof(u32) || len / sizeof(u32) % 2) { + dev_err(dev, "ieee80211-freq-limit wrong format"); + return -EPROTO; + } + wiphy->n_freq_limits = len / sizeof(u32) / 2; + + wiphy->freq_limits = kzalloc(wiphy->n_freq_limits * sizeof(*wiphy->freq_limits), + GFP_KERNEL); + if (!wiphy->freq_limits) { + err = -ENOMEM; + goto out; + } + + p = NULL; + for (i = 0; i < wiphy->n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &wiphy->freq_limits[i]; + + p = of_prop_next_u32(prop, p, &limit->start_freq_khz); + if (!p) { + err = -EINVAL; + goto out; + } + + p = of_prop_next_u32(prop, p, &limit->end_freq_khz); + if (!p) { + err = -EINVAL; + goto out; + } + + if (!limit->start_freq_khz || + !limit->end_freq_khz || + limit->start_freq_khz >= limit->end_freq_khz) { + err = -EINVAL; + goto out; + } + } + + return 0; + +out: + dev_err(dev, "Failed to get limits: %d\n", err); + kfree(wiphy->freq_limits); + wiphy->n_freq_limits = 0; + + return err; +} +EXPORT_SYMBOL(wiphy_read_of_freq_limits); + +static bool wiphy_freq_limits_valid_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan) +{ + u32 bw = MHZ_TO_KHZ(20); + int i; + + for (i = 0; i < wiphy->n_freq_limits; i++) { + struct ieee80211_freq_range *limit = &wiphy->freq_limits[i]; + + if (reg_does_bw_fit(limit, MHZ_TO_KHZ(chan->center_freq), bw)) + return true; + } + + return false; +} + +static void wiphy_freq_limits_apply(struct wiphy *wiphy) +{ + enum nl80211_band band; + int i; + + if (!wiphy->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, chan)) { + pr_debug("Disabling freq %d MHz as it's out of OF limits\n", + chan->center_freq); + chan->flags |= IEEE80211_CHAN_DISABLED; + } + } + } +} + /* * Note that right now we assume the desired channel bandwidth * is always 20 MHz for each individual channel (HT40 uses 20 MHz @@ -1693,6 +1807,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, for (band = 0; band < NUM_NL80211_BANDS; band++) handle_band(wiphy, initiator, wiphy->bands[band]); + wiphy_freq_limits_apply(wiphy); + reg_process_beacons(wiphy); reg_process_ht_flags(wiphy); reg_call_notifier(wiphy, lr); @@ -1800,6 +1916,8 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, bands_set++; } + wiphy_freq_limits_apply(wiphy); + /* * no point in calling this if it won't have any effect * on your device's supported bands.