diff options
Diffstat (limited to 'drivers/net/wireless/ath/wcn36xx/main.c')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/main.c | 107 |
1 files changed, 94 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 9575d7373bf2..95ea7d040d8c 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -331,6 +331,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw) INIT_LIST_HEAD(&wcn->vif_list); spin_lock_init(&wcn->dxe_lock); + spin_lock_init(&wcn->survey_lock); return 0; @@ -392,11 +393,41 @@ static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch) { struct ieee80211_vif *vif = NULL; struct wcn36xx_vif *tmp; + struct ieee80211_supported_band *band; + struct ieee80211_channel *channel = NULL; + unsigned long flags; + int i, j; + + for (i = 0; i < ARRAY_SIZE(wcn->hw->wiphy->bands); i++) { + band = wcn->hw->wiphy->bands[i]; + if (!band) + break; + for (j = 0; j < band->n_channels; j++) { + if (HW_VALUE_CHANNEL(band->channels[j].hw_value) == ch) { + channel = &band->channels[j]; + break; + } + } + if (channel) + break; + } + + if (!channel) { + wcn36xx_err("Cannot tune to channel %d\n", ch); + return; + } + + spin_lock_irqsave(&wcn->survey_lock, flags); + wcn->band = band; + wcn->channel = channel; + spin_unlock_irqrestore(&wcn->survey_lock, flags); list_for_each_entry(tmp, &wcn->vif_list, list) { vif = wcn36xx_priv_to_vif(tmp); wcn36xx_smd_switch_channel(wcn, vif, ch); } + + return; } static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) @@ -1326,6 +1357,49 @@ static void wcn36xx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } } +static int wcn36xx_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct wcn36xx *wcn = hw->priv; + struct ieee80211_supported_band *sband; + struct wcn36xx_chan_survey *chan_survey; + int band_idx; + unsigned long flags; + + sband = wcn->hw->wiphy->bands[NL80211_BAND_2GHZ]; + band_idx = idx; + if (band_idx >= sband->n_channels) { + band_idx -= sband->n_channels; + sband = wcn->hw->wiphy->bands[NL80211_BAND_5GHZ]; + } + + if (!sband || band_idx >= sband->n_channels) + return -ENOENT; + + spin_lock_irqsave(&wcn->survey_lock, flags); + + chan_survey = &wcn->chan_survey[idx]; + survey->channel = &sband->channels[band_idx]; + survey->noise = chan_survey->rssi - chan_survey->snr; + survey->filled = 0; + + if (chan_survey->rssi > -100 && chan_survey->rssi < 0) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + if (survey->channel == wcn->channel) + survey->filled |= SURVEY_INFO_IN_USE; + + spin_unlock_irqrestore(&wcn->survey_lock, flags); + + wcn36xx_dbg(WCN36XX_DBG_MAC, + "ch %d rssi %d snr %d noise %d filled %x freq %d\n", + HW_VALUE_CHANNEL(survey->channel->hw_value), + chan_survey->rssi, chan_survey->snr, survey->noise, + survey->filled, survey->channel->center_freq); + + return 0; +} + static const struct ieee80211_ops wcn36xx_ops = { .start = wcn36xx_start, .stop = wcn36xx_stop, @@ -1354,6 +1428,7 @@ static const struct ieee80211_ops wcn36xx_ops = { .ipv6_addr_change = wcn36xx_ipv6_addr_change, #endif .flush = wcn36xx_flush, + .get_survey = wcn36xx_get_survey, CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; @@ -1446,25 +1521,20 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, { struct device_node *mmio_node; struct device_node *iris_node; - struct resource *res; int index; int ret; /* Set TX IRQ */ - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx"); - if (!res) { - wcn36xx_err("failed to get tx_irq\n"); - return -ENOENT; - } - wcn->tx_irq = res->start; + ret = platform_get_irq_byname(pdev, "tx"); + if (ret < 0) + return ret; + wcn->tx_irq = ret; /* Set RX IRQ */ - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx"); - if (!res) { - wcn36xx_err("failed to get rx_irq\n"); - return -ENOENT; - } - wcn->rx_irq = res->start; + ret = platform_get_irq_byname(pdev, "rx"); + if (ret < 0) + return ret; + wcn->rx_irq = ret; /* Acquire SMSM tx enable handle */ wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev, @@ -1513,6 +1583,9 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn, if (iris_node) { if (of_device_is_compatible(iris_node, "qcom,wcn3620")) wcn->rf_id = RF_IRIS_WCN3620; + if (of_device_is_compatible(iris_node, "qcom,wcn3660") || + of_device_is_compatible(iris_node, "qcom,wcn3660b")) + wcn->rf_id = RF_IRIS_WCN3660; if (of_device_is_compatible(iris_node, "qcom,wcn3680")) wcn->rf_id = RF_IRIS_WCN3680; of_node_put(iris_node); @@ -1535,6 +1608,7 @@ static int wcn36xx_probe(struct platform_device *pdev) void *wcnss; int ret; const u8 *addr; + int n_channels; wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n"); @@ -1562,6 +1636,13 @@ static int wcn36xx_probe(struct platform_device *pdev) goto out_wq; } + n_channels = wcn_band_2ghz.n_channels + wcn_band_5ghz.n_channels; + wcn->chan_survey = devm_kmalloc(wcn->dev, n_channels, GFP_KERNEL); + if (!wcn->chan_survey) { + ret = -ENOMEM; + goto out_wq; + } + ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32)); if (ret < 0) { wcn36xx_err("failed to set DMA mask: %d\n", ret); |